diff --git a/openapi/openapi.yaml b/openapi/openapi.yaml index 641fe9aa..beb1c42a 100644 --- a/openapi/openapi.yaml +++ b/openapi/openapi.yaml @@ -23,8 +23,8 @@ tags: 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.' + - name: LavaFlow + description: 'Preview, not generally available: LavaFlow diagnoses a project''s issues and opens pull requests that fix them. It never merges. 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 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 @@ -71,6 +75,8 @@ tags: 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 +107,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 +363,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 +618,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`. content: application/json: schema: @@ -654,7 +660,7 @@ 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), 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`. content: application/json: schema: @@ -1018,7 +1024,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 +1032,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 +1572,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,6 +1996,208 @@ paths: application/json: schema: $ref: '#/components/schemas/Error' + /user/tokens/current: + delete: + tags: + - Account Sessions + summary: Revoke the calling platform token + description: | + 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: + '204': + description: Token revoked + '401': + description: Not authenticated, or not a platform token + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '403': + description: Forbidden - a project access token cannot revoke a platform token + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '500': + description: Failed to revoke the token + 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: + get: + tags: + - Account Sessions + summary: List your account's sign-in sessions + description: | + 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/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: A page of the account's sessions + content: + application/json: + schema: + $ref: '#/components/schemas/AccountSessionList' + '400': + description: Invalid or conflicting pagination parameters + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '401': + description: Not authenticated, or not a platform token + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '403': + description: Forbidden - a project access token cannot read account sessions + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '500': + description: Failed to list 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' + delete: + tags: + - 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: [] + responses: + '204': + description: Every other session ended + '401': + description: Not authenticated, or not a platform token + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '403': + description: Forbidden - a project access token cannot end account sessions + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '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: + - 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: [] + parameters: + - name: sessionId + in: path + required: true + description: The session ID, from `GET /user/sessions` + schema: + type: string + responses: + '204': + description: Session ended + '401': + description: Not authenticated, or not a platform token + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '403': + description: Forbidden - a project access token cannot end account sessions + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '404': + description: Session not found + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '500': + description: Failed to end the session + 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' /github/callback: get: tags: @@ -1998,19 +2206,29 @@ paths: description: | 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: - name: code in: query required: false - description: GitHub user authorization code. + description: GitHub user authorization code. Ignored when `state` is absent. schema: type: string - name: state in: query - required: true - description: Signed connect state generated by startGitConnect. + 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 @@ -2019,7 +2237,49 @@ paths: 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: + '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: @@ -2028,7 +2288,10 @@ paths: schema: type: string '400': - description: Invalid callback request or state + 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: @@ -2110,7 +2373,9 @@ paths: 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. + 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: [] @@ -2134,7 +2399,7 @@ paths: schema: $ref: '#/components/schemas/Error' '403': - description: Project limit exceeded for the user + 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: @@ -2816,7 +3081,7 @@ paths: schema: $ref: '#/components/schemas/ProjectConfigApplyResult' '400': - description: Malformed request body + 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: @@ -2929,11 +3194,12 @@ paths: 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 @@ -2991,8 +3257,9 @@ paths: 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 + 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: @@ -3103,8 +3370,15 @@ paths: 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`. operationId: setProjectGitProductionBranch security: - UserToken: [] @@ -3126,8 +3400,11 @@ paths: $ref: '#/components/schemas/ProjectGitConnection' '400': description: | - Malformed request body, or a production_branch that is not a valid - Git branch name + 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: @@ -3154,75 +3431,43 @@ paths: schema: $ref: '#/components/schemas/Error' '409': - description: A Git source transition is pending - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - '500': - description: Failed to set the production branch - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - /projects/{id}/git-connection: - get: - tags: - - Projects - - Git Connections - summary: Get a project's repo connection - operationId: getProjectGitConnection - security: - - UserToken: [] - - ProjectAccessToken: [] - parameters: - - $ref: '#/components/parameters/ProjectId' - responses: - '200': - description: The project's current repo connection - content: - application/json: - schema: - $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 + 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' - '404': - description: Project not found, or has no repo connection + '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: Failed to get project git connection + description: Failed to set the production branch content: application/json: schema: $ref: '#/components/schemas/Error' + /projects/{id}/git-connection/root-directory: put: tags: - Projects - Git Connections - summary: Connect or update a project's repo connection + summary: Set the directory a project builds from 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 + 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: [] @@ -3233,22 +3478,18 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/ConnectProjectGitRequest' + $ref: '#/components/schemas/SetProjectGitRootDirectoryRequest' responses: '200': - description: The project's repo connection + description: The project's repo connection, with the new root directory 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. + Malformed request body, or a root_directory that is absolute or + leaves the repository content: application/json: schema: @@ -3260,15 +3501,16 @@ paths: schema: $ref: '#/components/schemas/Error' '403': - description: | - Project not owned by the caller, or the selected repository is not - accessible through installation_id + description: Project not owned by the caller content: application/json: schema: $ref: '#/components/schemas/Error' '404': - description: Project or connection not found + description: | + 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: @@ -3276,37 +3518,49 @@ paths: '409': description: | A Git source transition is pending or complete, so the recorded - repository and root cannot be changed + 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 + description: Failed to set the root directory content: application/json: schema: $ref: '#/components/schemas/Error' - delete: + /projects/{id}/git-connection/owner-push: + get: tags: - Projects - Git Connections - summary: Disconnect a project's repo connection - operationId: disconnectProjectGit + summary: Check whether the project owner can push to the connected repository + description: | + 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`. + operationId: getProjectGitOwnerPush security: - UserToken: [] - ProjectAccessToken: [] parameters: - $ref: '#/components/parameters/ProjectId' responses: - '204': - description: Connection removed + '200': + description: Whether the project owner can push to the connected repository + content: + application/json: + schema: + $ref: '#/components/schemas/ProjectGitOwnerPush' '401': description: Unauthorized - invalid or missing token content: @@ -3320,12 +3574,230 @@ paths: schema: $ref: '#/components/schemas/Error' '404': - description: Project not found, or has no repo connection + 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' - '409': + '429': + description: | + 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' + '500': + description: Failed to check the project owner's access + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '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}/git-connection: + get: + tags: + - 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' + responses: + '200': + description: The project's current repo connection + content: + application/json: + schema: + $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: Project not found, or has no repo connection + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '500': + description: Failed to get project git connection + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + put: + tags: + - 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. + operationId: connectProjectGit + security: + - UserToken: [] + parameters: + - $ref: '#/components/parameters/ProjectId' + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/ConnectProjectGitRequest' + responses: + '200': + description: The project's repo connection + 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 + (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. A full-scope token gets `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: 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: + - Projects + - Git Connections + summary: Disconnect a project's repo connection + operationId: disconnectProjectGit + security: + - UserToken: [] + - ProjectAccessToken: [] + parameters: + - $ref: '#/components/parameters/ProjectId' + 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 + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '404': + description: Project not found, or has no repo connection + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '409': description: | A Git source transition is pending or complete, so the recorded repository cannot be disconnected @@ -3399,6 +3871,9 @@ paths: 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: [] @@ -3419,7 +3894,10 @@ paths: schema: $ref: '#/components/schemas/ProjectGitDeploySettings' '400': - description: Malformed request body, or frontend_app_root without frontend_name + 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: @@ -3456,43 +3934,55 @@ paths: application/json: schema: $ref: '#/components/schemas/Error' - /projects/{id}/databases/{databaseName}/queries: + /projects/{id}/git-deployment-runs: get: tags: - - Databases - summary: Get database queries + - Projects + - Git Connections + summary: List a project's Git deployment runs 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. + 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. - **SUPERAGENT plan required.** This endpoint is only available to projects owned - by users on the SUPERAGENT billing plan. - operationId: getProjectDatabaseQueries + 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. + operationId: listGitDeploymentRuns security: - UserToken: [] - ProjectAccessToken: [] parameters: - $ref: '#/components/parameters/ProjectId' - - $ref: '#/components/parameters/DatabaseName' - - name: limit + - $ref: '#/components/parameters/Limit' + - $ref: '#/components/parameters/IssueCursor' + - name: status in: query - description: Maximum number of queries to return. + required: false + description: Return only runs in this status. schema: - type: integer - minimum: 1 - maximum: 100 - default: 10 + $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: Database query performance retrieved + description: Successful response content: application/json: schema: - $ref: '#/components/schemas/DatabaseQueryPerformanceResponse' + $ref: '#/components/schemas/PaginatedGitDeploymentRuns' '400': - description: Bad request - invalid query parameters + description: A filter or the cursor is invalid content: application/json: schema: @@ -3504,49 +3994,157 @@ 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 or database not found - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - '500': - description: Internal server error + description: Project not found content: application/json: schema: $ref: '#/components/schemas/Error' - /deployments: + /projects/{id}/git-deployment-runs/{runId}: get: tags: - Projects - summary: List deployments across a user's projects + - Git Connections + summary: Get a Git deployment run 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. + Returns one deployment run: the commit it deployed, its status, the + migration runs it started, and why it failed or was skipped. - 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. + Project access tokens can read runs, including read-only ones. + operationId: getGitDeploymentRun + security: + - UserToken: [] + - ProjectAccessToken: [] + parameters: + - $ref: '#/components/parameters/ProjectId' + - 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/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' + '404': + description: Project or run not found + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + /projects/{id}/databases/{databaseName}/queries: + get: + tags: + - 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/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 + 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 or database not found + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '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. + + 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 @@ -3936,6 +4534,8 @@ paths: - 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 @@ -3981,6 +4581,10 @@ paths: 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`. responses: '200': description: Existing function updated; its deployment was started or queued @@ -3997,7 +4601,8 @@ paths: '400': description: | Bad request (invalid file, too large, etc.), an unknown - `visibility`, or `visibility` and `is_public` disagree + `visibility`, `visibility` and `is_public` disagree, or a + malformed `commit` content: application/json: schema: @@ -4383,10 +4988,13 @@ paths: 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 @@ -4505,21 +5113,20 @@ paths: application/json: schema: $ref: '#/components/schemas/Error' - /durable-functions/{functionId}/executions/{executionId}/messages: - post: + /durable-functions/{functionId}/executions/{executionId}: + get: tags: - Durable Functions - summary: Send a message to a durable execution from an application + summary: Get a durable execution from an application 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. + 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. + **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 @@ -4528,12 +5135,13 @@ paths: **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. + Only a service key holding `*` reaches an execution that is still + `pending`. 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 + The response is the one `GET + /projects/{id}/durable-functions/{functionId}/executions/{executionId}` + returns. It never carries `client_token`. + operationId: getDurableExecutionFromApplication security: - AnonKey: [] - ServiceRoleKey: [] @@ -4541,36 +5149,14 @@ paths: 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' 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. - content: - application/json: - schema: - $ref: '#/components/schemas/DurableMessage' - '400': - description: The name, data or idempotency key is invalid + description: Successful response content: application/json: schema: - $ref: '#/components/schemas/Error' + $ref: '#/components/schemas/DurableExecution' '401': description: Missing or invalid credential content: @@ -4596,50 +5182,52 @@ paths: 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. - 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. + 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 plan terms for the request could not be read. Retry with backoff. + description: | + 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' - get: + /durable-functions/{functionId}/executions/{executionId}/stop: + post: tags: - Durable Functions - summary: List a durable execution's messages from an application + summary: Stop a durable execution from an application 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. + Cancels a running execution with the credential that started it. Its + completed steps are not undone. - Access follows the same rules as sending. - operationId: listDurableMessagesFromApplication + 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: [] @@ -4648,23 +5236,15 @@ paths: - $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: Successful response - content: - application/json: - schema: - $ref: '#/components/schemas/DurableMessageList' - '400': - description: A filter is invalid + 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/Error' + $ref: '#/components/schemas/DurableExecution' '401': description: Missing or invalid credential content: @@ -4684,14 +5264,23 @@ paths: '404': description: | Durable function or execution not found, or the credential cannot - reach the execution. + 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 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' '429': description: | - The function's or the project's function rate limit, which lists + 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: @@ -4699,19 +5288,236 @@ paths: schema: $ref: '#/components/schemas/Error' '503': - description: The plan terms for the request could not be read. Retry with backoff. + 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: + type: integer content: application/json: schema: $ref: '#/components/schemas/Error' - /functions/resolve: - get: + /durable-functions/{functionId}/executions/{executionId}/messages: + post: tags: - - Functions - summary: Resolve function name for invocation + - Durable Functions + summary: Send a message to a durable execution from an application description: | - Resolves a DNS-safe function name to its function ID and invocation URL within the caller's project. - + 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 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/SendDurableMessageRequest' + 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. + content: + application/json: + schema: + $ref: '#/components/schemas/DurableMessage' + '400': + description: The name, data or idempotency key is invalid + 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. + 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. + 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. + 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: + tags: + - Durable Functions + summary: List a durable execution's messages from an application + 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. + + 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: Successful response + content: + application/json: + schema: + $ref: '#/components/schemas/DurableMessageList' + '400': + description: A filter is invalid + 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. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '404': + description: | + Durable function or execution not found, or the credential cannot + reach the execution. + 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. + 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' + /functions/resolve: + get: + tags: + - Functions + summary: Resolve function name for invocation + 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 @@ -5030,6 +5836,8 @@ paths: 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 @@ -5126,99 +5934,285 @@ paths: application/json: schema: $ref: '#/components/schemas/Error' - /projects/{id}/functions/{functionId}/schedulers: + /projects/{id}/notifications: get: tags: - - Functions - summary: List schedulers for a function - operationId: listFunctionSchedulers + - 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' - - $ref: '#/components/parameters/FunctionId' responses: '200': - description: Function schedulers + description: Notification settings content: application/json: schema: - $ref: '#/components/schemas/FunctionSchedulerListResponse' + $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: Function not found + description: Project not found content: application/json: schema: $ref: '#/components/schemas/Error' - post: + put: 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 + - 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' - - $ref: '#/components/parameters/FunctionId' requestBody: required: true content: application/json: schema: - $ref: '#/components/schemas/CreateFunctionSchedulerRequest' + $ref: '#/components/schemas/UpdateNotificationSettingsRequest' responses: - '201': - description: Scheduler created + '200': + description: Saved content: application/json: schema: - $ref: '#/components/schemas/FunctionScheduler' + $ref: '#/components/schemas/NotificationSettings' '400': - description: | - Invalid schedule, geofenced region, a scheduler of this name - already exists on the function, or the function is not active. + 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' '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: The request used a `read_only` project access token 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}/functions/{functionId}/schedulers/{schedulerId}: - get: + /projects/{id}/notifications/webhook-secret: + post: tags: - - Functions - summary: Get a function scheduler - operationId: getFunctionScheduler + - Notifications + summary: Rotate the webhook signing secret + description: | + 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/FunctionId' - - $ref: '#/components/parameters/SchedulerId' responses: '200': - description: Function scheduler + description: Rotated content: application/json: schema: - $ref: '#/components/schemas/FunctionScheduler' + $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 + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '409': + description: No webhook is configured. Set `webhook.url` first. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + /projects/{id}/notifications/test: + post: + tags: + - Notifications + summary: Send a test notification + description: | + 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' + responses: + '200': + 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/Error' + '404': + description: Project not found + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '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' + '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: + - 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 + content: + application/json: + schema: + $ref: '#/components/schemas/FunctionSchedulerListResponse' + '404': + description: Function not found + 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': + 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: | + 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: + - Functions + summary: Get a function scheduler + operationId: getFunctionScheduler + security: + - UserToken: [] + - ProjectAccessToken: [] + parameters: + - $ref: '#/components/parameters/ProjectId' + - $ref: '#/components/parameters/FunctionId' + - $ref: '#/components/parameters/SchedulerId' + responses: + '200': + description: Function scheduler + content: + application/json: + schema: + $ref: '#/components/schemas/FunctionScheduler' '404': description: Function or scheduler not found content: @@ -5323,6 +6317,7 @@ paths: operationId: listDurableFunctions security: - UserToken: [] + - ProjectAccessToken: [] parameters: - $ref: '#/components/parameters/ProjectId' - $ref: '#/components/parameters/Page' @@ -5369,6 +6364,7 @@ paths: operationId: createDurableFunction security: - UserToken: [] + - ProjectAccessToken: [] parameters: - $ref: '#/components/parameters/ProjectId' requestBody: @@ -5447,6 +6443,10 @@ paths: 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`. responses: '200': description: Existing durable function updated; its deployment was started or queued @@ -5463,8 +6463,9 @@ paths: '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 + 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: @@ -5507,6 +6508,7 @@ paths: operationId: getDurableFunction security: - UserToken: [] + - ProjectAccessToken: [] parameters: - $ref: '#/components/parameters/ProjectId' - $ref: '#/components/parameters/DurableFunctionId' @@ -5540,6 +6542,7 @@ paths: operationId: deleteDurableFunction security: - UserToken: [] + - ProjectAccessToken: [] parameters: - $ref: '#/components/parameters/ProjectId' - $ref: '#/components/parameters/DurableFunctionId' @@ -5563,6 +6566,7 @@ paths: operationId: listDurableFunctionDeployments security: - UserToken: [] + - ProjectAccessToken: [] parameters: - $ref: '#/components/parameters/ProjectId' - $ref: '#/components/parameters/DurableFunctionId' @@ -5594,6 +6598,7 @@ paths: operationId: listDurableFunctionSchedulers security: - UserToken: [] + - ProjectAccessToken: [] parameters: - $ref: '#/components/parameters/ProjectId' - $ref: '#/components/parameters/DurableFunctionId' @@ -5625,6 +6630,7 @@ paths: operationId: createDurableFunctionScheduler security: - UserToken: [] + - ProjectAccessToken: [] parameters: - $ref: '#/components/parameters/ProjectId' - $ref: '#/components/parameters/DurableFunctionId' @@ -5672,6 +6678,7 @@ paths: operationId: getDurableFunctionScheduler security: - UserToken: [] + - ProjectAccessToken: [] parameters: - $ref: '#/components/parameters/ProjectId' - $ref: '#/components/parameters/DurableFunctionId' @@ -5696,6 +6703,7 @@ paths: operationId: updateDurableFunctionScheduler security: - UserToken: [] + - ProjectAccessToken: [] parameters: - $ref: '#/components/parameters/ProjectId' - $ref: '#/components/parameters/DurableFunctionId' @@ -5734,6 +6742,7 @@ paths: operationId: deleteDurableFunctionScheduler security: - UserToken: [] + - ProjectAccessToken: [] parameters: - $ref: '#/components/parameters/ProjectId' - $ref: '#/components/parameters/DurableFunctionId' @@ -5772,6 +6781,7 @@ paths: operationId: startDurableExecution security: - UserToken: [] + - ProjectAccessToken: [] parameters: - $ref: '#/components/parameters/ProjectId' - $ref: '#/components/parameters/DurableFunctionId' @@ -5859,6 +6869,7 @@ paths: operationId: listDurableExecutions security: - UserToken: [] + - ProjectAccessToken: [] parameters: - $ref: '#/components/parameters/ProjectId' - $ref: '#/components/parameters/DurableFunctionId' @@ -5900,6 +6911,7 @@ paths: operationId: getDurableExecution security: - UserToken: [] + - ProjectAccessToken: [] parameters: - $ref: '#/components/parameters/ProjectId' - $ref: '#/components/parameters/DurableFunctionId' @@ -5919,9 +6931,18 @@ paths: $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. + 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: @@ -5949,6 +6970,7 @@ paths: operationId: listDurableExecutionOperations security: - UserToken: [] + - ProjectAccessToken: [] parameters: - $ref: '#/components/parameters/ProjectId' - $ref: '#/components/parameters/DurableFunctionId' @@ -6001,6 +7023,7 @@ paths: operationId: stopDurableExecution security: - UserToken: [] + - ProjectAccessToken: [] parameters: - $ref: '#/components/parameters/ProjectId' - $ref: '#/components/parameters/DurableFunctionId' @@ -6028,9 +7051,20 @@ paths: $ref: '#/components/schemas/Error' '503': description: | - Durable execution is not available in this environment. Either the + 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. + 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: @@ -6444,7 +7478,9 @@ paths: 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`. operationId: registerDurableCallback security: [] requestBody: @@ -6552,7 +7588,7 @@ paths: schema: $ref: '#/components/schemas/DurableCallbackOutcome' '400': - description: The token is missing, or `result` is missing, null, not JSON, or larger than 64 KiB + description: The token is missing or malformed, or `result` is missing, null, not JSON, or larger than 64 KiB content: application/json: schema: @@ -6630,7 +7666,7 @@ paths: schema: $ref: '#/components/schemas/DurableCallbackOutcome' '400': - description: The token is missing, or the error's `type` or `message` is invalid + description: The token is missing or malformed, or the error's `type` or `message` is invalid content: application/json: schema: @@ -6658,7 +7694,7 @@ paths: schema: $ref: '#/components/schemas/Error' '413': - description: The request body is larger than 72 KiB + description: The request body is larger than 200 KiB content: application/json: schema: @@ -6695,7 +7731,7 @@ paths: schema: $ref: '#/components/schemas/DurableCallbackOutcome' '400': - description: The token is missing + description: The token is missing or malformed content: application/json: schema: @@ -6827,384 +7863,418 @@ paths: application/json: schema: $ref: '#/components/schemas/Error' - /projects/{id}/issues: + /projects/{id}/capabilities: get: tags: - - Issues - summary: List issues + - Projects + summary: List a project's capabilities 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. + 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: - Project access tokens can list issues, including read-only ones. - operationId: listIssues + | ID | Available for this project when | + | --- | --- | + | `lavaflow` | LavaFlow is released, offered to the project's owner, and included in the owner's plan | + + 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/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: Successful response + description: Capabilities for this project content: application/json: schema: - $ref: '#/components/schemas/PaginatedIssues' - '400': - description: A filter or the cursor is invalid + $ref: '#/components/schemas/CapabilityList' + '401': + description: Not authenticated content: application/json: schema: $ref: '#/components/schemas/Error' '404': - description: Project not found. Code `feature_unavailable` means issues are not available in this environment. + description: Project not found content: application/json: schema: $ref: '#/components/schemas/Error' - /projects/{id}/issues/{issueId}: + /lavaflow/settings: get: tags: - - Issues - summary: Get an issue + - LavaFlow + summary: Get LavaFlow settings description: | - Returns one issue: the resource that raised it, how often and when it - was seen, and its status. + 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. - Project access tokens can read issues, including read-only ones. - operationId: getIssue + `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/IssueId' + - $ref: '#/components/parameters/ProjectIdQuery' responses: '200': - description: Successful response + description: The project's LavaFlow settings content: application/json: schema: - $ref: '#/components/schemas/Issue' + $ref: '#/components/schemas/LavaflowSettings' + '400': + description: '`project_id` is missing or not a UUID.' + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '401': + description: Not authenticated + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '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: Issue not found. Code `feature_unavailable` means issues are not available in this environment. + 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' - patch: + put: tags: - - Issues - summary: Update an issue + - LavaFlow + summary: Update LavaFlow settings 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. + 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. LavaFlow sends this project's logs and source code to an AI + service that Volcano operates. - Setting the status an issue already has is safe to repeat. - operationId: updateIssue + Only the project's owner can save, with a platform token, while their + account is active. A full-scope project access token gets `403` with + code `person_required`; a read-only one is refused as read-only first, + without a code, and so is the owner of a read-only account. + + 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 off, + sending `enabled: false` and nothing else to change. 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/IssueId' requestBody: required: true content: application/json: schema: - $ref: '#/components/schemas/UpdateIssueRequest' + $ref: '#/components/schemas/LavaflowSettingsUpdate' responses: '200': - description: Updated + description: Saved content: application/json: schema: - $ref: '#/components/schemas/Issue' + $ref: '#/components/schemas/LavaflowSettings' '400': - description: The request body is invalid + description: 'The body is invalid: `project_id` missing or not a UUID, no field to change, an unknown field or autonomy, or `custom_context` or `system_prompt` over 4000 characters.' content: application/json: schema: $ref: '#/components/schemas/Error' - '404': - description: Issue not found. Code `feature_unavailable` means issues are not available in this environment. + '401': + description: Not authenticated 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 + '403': + description: 'Code `person_required` means a full-scope project access token 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 `volcano login` token whose sign-in is live, or the owner''s GitHub account can''t push to the project''s repository. 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/AutofixSettings' + $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. + 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 not only turn LavaFlow off on a project with LavaFlow records. content: application/json: schema: $ref: '#/components/schemas/Error' - '501': - description: Autofix is not available in local mode. + '413': + description: Request body exceeds 131,072 bytes + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '429': + description: | + The save turns on a setting only the project's owner may turn on, + 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: The owner's plan could not be resolved. Retry later. + description: | + The save turns on a setting only the project's owner may turn on, + 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' - put: + /lavaflow/stats: + get: tags: - - Autofix - summary: Replace autofix settings + - LavaFlow + summary: Get LavaFlow stats 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`. - - 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 + 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 and `days`. + operationId: getLavaflowStats security: - UserToken: [] + - ProjectAccessToken: [] parameters: - - $ref: '#/components/parameters/ProjectId' - requestBody: - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/UpdateAutofixSettingsRequest' + - $ref: '#/components/parameters/ProjectIdQuery' + - $ref: '#/components/parameters/LavaflowDays' responses: '200': - description: Saved + description: The project's LavaFlow activity per day content: application/json: schema: - $ref: '#/components/schemas/AutofixSettings' + $ref: '#/components/schemas/LavaflowStats' '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. - 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. + description: '`project_id` is missing or not a UUID, or `days` is outside 1 to 90.' 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. + '401': + description: Not authenticated content: application/json: schema: $ref: '#/components/schemas/Error' - '501': - description: Autofix is not available in local mode. + '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: Turning autofix on needs the owner's plan, which could not be resolved. Nothing was saved. Retry later. + '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}/autofix/api-key: - delete: + /lavaflow/resources: + get: tags: - - Autofix - summary: Delete the API key + - LavaFlow + summary: List LavaFlow's resources 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. + 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 with activity in the window is listed too, so the + counts add up to `GET /lavaflow/stats`. - Project access tokens are refused. - operationId: deleteAutofixAPIKey + `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. + operationId: listLavaflowResources security: - UserToken: [] + - ProjectAccessToken: [] parameters: - - $ref: '#/components/parameters/ProjectId' + - $ref: '#/components/parameters/ProjectIdQuery' + - $ref: '#/components/parameters/LavaflowDays' responses: '200': - description: Deleted + description: The project's resources with LavaFlow's activity content: application/json: schema: - $ref: '#/components/schemas/AutofixSettings' - '403': - description: The request used a project access token. Only a person deletes the key. + $ref: '#/components/schemas/LavaflowResourceList' + '400': + description: '`project_id` is missing or not a UUID, or `days` is outside 1 to 90.' 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. + '401': + description: Not authenticated content: application/json: schema: $ref: '#/components/schemas/Error' - '501': - description: Autofix is not available in local mode. + '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}/issues/{issueId}/autofix-runs: - 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/runs: + get: tags: - - Autofix - summary: Diagnose an issue + - LavaFlow + summary: List LavaFlow runs 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 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 + Pages the project's LavaFlow runs, newest first. A page carries no run + text; read a run for its diagnosis, log lines and diff. + operationId: listLavaflowRuns security: - UserToken: [] + - ProjectAccessToken: [] parameters: - - $ref: '#/components/parameters/ProjectId' - - $ref: '#/components/parameters/IssueId' + - $ref: '#/components/parameters/ProjectIdQuery' + - $ref: '#/components/parameters/LavaflowRunLimit' + - $ref: '#/components/parameters/LavaflowRunCursor' + - $ref: '#/components/parameters/LavaflowRunStatusFilter' + - $ref: '#/components/parameters/LavaflowResourceIdFilter' responses: - '202': - description: Queued + '200': + description: A page of runs content: application/json: schema: - $ref: '#/components/schemas/AutofixRun' + $ref: '#/components/schemas/PaginatedLavaflowRuns' '400': - description: Code `feature_unavailable` means the project's provider is `volcano` and Volcano-managed models are not available in this environment. + description: '`project_id` is missing or not a UUID, or the cursor, limit or status is invalid.' + 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 autofix, or the request used a project access token. + 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: Project or issue not found. Code `feature_unavailable` means autofix is not available in this environment. + 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' - '409': - description: Autofix is off for the project, or the issue already has a queued or running run. + /lavaflow/runs/{run_id}: + get: + tags: + - LavaFlow + summary: Get a LavaFlow run + description: | + Returns a run, with its diagnosis, the log lines it cites, its diff and + its review. 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. + operationId: getLavaflowRun + security: + - UserToken: [] + - ProjectAccessToken: [] + parameters: + - $ref: '#/components/parameters/LavaflowRunId' + - $ref: '#/components/parameters/ItemProjectIdQuery' + responses: + '200': + description: The run + content: + application/json: + schema: + $ref: '#/components/schemas/LavaflowRun' + '400': + description: '`project_id` is given and not a UUID.' content: application/json: schema: $ref: '#/components/schemas/Error' - '429': - description: The project started its limit of runs in the last 24 hours. + '401': + description: Not authenticated content: application/json: schema: $ref: '#/components/schemas/Error' - '501': - description: Autofix is not available in local mode. + '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: The owner's plan could not be resolved. Retry later. + '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' - /projects/{id}/autofix-runs: + /projects/{id}/issues: get: tags: - - Autofix - summary: List autofix runs + - Issues + summary: List issues description: | - Lists the project's autofix runs, newest first. Runs stay readable after - autofix is turned off, and where autofix is not available. + 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 runs, including read-only ones. - operationId: listAutofixRuns + Project access tokens can list issues, including read-only ones. + operationId: listIssues security: - UserToken: [] - ProjectAccessToken: [] @@ -7212,26 +8282,26 @@ paths: - $ref: '#/components/parameters/ProjectId' - $ref: '#/components/parameters/Limit' - $ref: '#/components/parameters/IssueCursor' - - name: issue_id + - name: status in: query required: false - description: Return only runs for this issue. + description: Return only issues in this status. schema: - type: string - format: uuid - - name: status + $ref: '#/components/schemas/IssueStatus' + - name: resource_id in: query required: false - description: Return only runs in this status. + description: Return only issues raised by this function or frontend. schema: - $ref: '#/components/schemas/AutofixRunStatus' + type: string + format: uuid responses: '200': description: Successful response content: application/json: schema: - $ref: '#/components/schemas/PaginatedAutofixRuns' + $ref: '#/components/schemas/PaginatedIssues' '400': description: A filter or the cursor is invalid content: @@ -7239,50 +8309,79 @@ paths: schema: $ref: '#/components/schemas/Error' '404': - description: Project not found. + description: Project not found. Code `feature_unavailable` means issues are not available in this environment. content: application/json: schema: $ref: '#/components/schemas/Error' - '501': - description: Autofix is not available in local mode. + /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/Issue' + '404': + description: Issue not found. Code `feature_unavailable` means issues are not available in this environment. content: application/json: schema: $ref: '#/components/schemas/Error' - /projects/{id}/autofix-runs/{runId}: - get: + patch: tags: - - Autofix - summary: Get an autofix run + - Issues + summary: Update an issue 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. + 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. - Project access tokens can read runs, including read-only ones. - operationId: getAutofixRun + Setting the status an issue already has is safe to repeat. + operationId: updateIssue security: - UserToken: [] - ProjectAccessToken: [] parameters: - $ref: '#/components/parameters/ProjectId' - - $ref: '#/components/parameters/AutofixRunId' + - $ref: '#/components/parameters/IssueId' + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/UpdateIssueRequest' responses: '200': - description: Successful response + description: Updated content: application/json: schema: - $ref: '#/components/schemas/AutofixRun' - '404': - description: Project or run not found. + $ref: '#/components/schemas/Issue' + '400': + description: The request body is invalid content: application/json: schema: $ref: '#/components/schemas/Error' - '501': - description: Autofix is not available in local mode. + '404': + description: Issue not found. Code `feature_unavailable` means issues are not available in this environment. content: application/json: schema: @@ -7557,38 +8656,1039 @@ paths: application/json: schema: $ref: '#/components/schemas/Error' - /projects/{id}/frontends: + /projects/{id}/frontends: + get: + tags: + - Frontends + summary: List all frontends 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 + 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 + content: + application/json: + schema: + $ref: '#/components/schemas/PaginatedFrontends' + '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 + 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' + post: + tags: + - Frontends + summary: Create a new frontend deployment + 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.3 (`>=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' + 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: + '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: Project not found + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '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: + - Frontends + summary: Get frontend details + operationId: getFrontend + security: + - UserToken: [] + - ProjectAccessToken: [] + parameters: + - $ref: '#/components/parameters/ProjectId' + - $ref: '#/components/parameters/FrontendId' + 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' + '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' + delete: + tags: + - Frontends + summary: Delete a frontend + 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 + security: + - UserToken: [] + - ProjectAccessToken: [] + parameters: + - $ref: '#/components/parameters/ProjectId' + - $ref: '#/components/parameters/FrontendId' + 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 + 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' + '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: + - Frontends + summary: Redeploy frontend using latest uploaded artifact + 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 + security: + - UserToken: [] + - ProjectAccessToken: [] + parameters: + - $ref: '#/components/parameters/ProjectId' + - $ref: '#/components/parameters/FrontendId' + responses: + '200': + description: Frontend redeploy started or queued + 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' + '404': + description: Frontend not found + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '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' + '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: + - Frontends + summary: Get frontend custom domain status + description: | + 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: + - UserToken: [] + - ProjectAccessToken: [] + parameters: + - $ref: '#/components/parameters/ProjectId' + - $ref: '#/components/parameters/FrontendId' + 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 + 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' + post: + tags: + - Frontends + summary: Configure frontend custom domain + deprecated: true + description: | + 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: + $ref: '#/components/schemas/CreateFrontendCustomDomainRequest' + 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 + content: + application/json: + schema: + $ref: '#/components/schemas/FrontendCustomDomainResponse' + '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, 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: Service unavailable - custom domain provisioning is temporarily unavailable + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + delete: + tags: + - Frontends + summary: Delete frontend custom domain + description: | + 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: + - UserToken: [] + - ProjectAccessToken: [] + parameters: + - $ref: '#/components/parameters/ProjectId' + - $ref: '#/components/parameters/FrontendId' + responses: + '204': + description: Custom domain detach scheduled + '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 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: + - Frontends + summary: List a frontend's custom domains + description: | + 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: + - UserToken: [] + - ProjectAccessToken: [] + responses: + '200': + description: The frontend's custom domains + content: + application/json: + schema: + $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' + post: + tags: + - 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. + + 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: + - UserToken: [] + - ProjectAccessToken: [] + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/CreateFrontendDomainRequest' + responses: + '200': + description: The frontend already has this hostname, or its TLS mode was switched in place + content: + application/json: + schema: + $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: 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: + - Frontends + summary: Get a frontend custom domain + operationId: getFrontendDomain + security: + - UserToken: [] + - ProjectAccessToken: [] + responses: + '200': + description: The custom domain + content: + application/json: + schema: + $ref: '#/components/schemas/FrontendCustomDomainResponse' + '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 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: + - Frontends + summary: Set or clear a custom domain's redirect + description: | + `{"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: + - UserToken: [] + - ProjectAccessToken: [] + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/UpdateFrontendCustomDomainRequest' + responses: + '200': + description: The updated custom domain + content: + application/json: + schema: + $ref: '#/components/schemas/FrontendCustomDomainResponse' + '400': + 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: 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 or custom domain not found, or the domain is being removed (`domain_status: detaching`)' + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '409': + description: Other domains of the frontend redirect to this one; the message names them + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '500': + description: Failed to update the custom domain + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + delete: + tags: + - 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: + - UserToken: [] + - ProjectAccessToken: [] + responses: + '204': + description: Custom domain detach scheduled + '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 or custom domain not found + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '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' + '500': + description: Failed to remove the custom domain + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + /projects/{id}/frontends/{frontendId}/deployments: + get: + tags: + - Frontends + summary: List frontend deployments + operationId: listFrontendDeployments + security: + - UserToken: [] + - ProjectAccessToken: [] + parameters: + - $ref: '#/components/parameters/ProjectId' + - $ref: '#/components/parameters/FrontendId' + - $ref: '#/components/parameters/Page' + - $ref: '#/components/parameters/Limit' + responses: + '200': + description: Successful response + content: + application/json: + schema: + $ref: '#/components/schemas/PaginatedFrontendDeployments' + '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' + post: + tags: + - Frontends + summary: Deploy an existing build to a frontend + description: | + 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: + - UserToken: [] + - ProjectAccessToken: [] + parameters: + - $ref: '#/components/parameters/ProjectId' + - $ref: '#/components/parameters/FrontendId' + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/CreateFrontendDeploymentRequest' + responses: + '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' + '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, or `code: source_deployment_not_found` when the source deployment is not in this project.' + content: + application/json: + schema: + $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_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' + '429': + description: Monthly build-minutes allowance exceeded + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '500': + description: Internal server error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '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: Service unavailable - frontend workflow configuration missing, or the build-minutes check is temporarily unavailable; retry later. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + /projects/{id}/frontends/{frontendId}/candidates: get: tags: - Frontends - summary: List all frontends in a project + summary: List a frontend's Candidates 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 + 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: - 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/FrontendId' responses: '200': - description: Successful response + description: The frontend's Candidates content: application/json: schema: - $ref: '#/components/schemas/PaginatedFrontends' + $ref: '#/components/schemas/FrontendCandidateList' '400': - description: Bad request - invalid project identifier + description: Bad request - invalid identifier content: application/json: schema: @@ -7606,7 +9706,7 @@ paths: schema: $ref: '#/components/schemas/Error' '404': - description: Project not found + description: Frontend not found content: application/json: schema: @@ -7620,40 +9720,31 @@ paths: post: tags: - Frontends - summary: Create a new frontend deployment - 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 + 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: - UserToken: [] - ProjectAccessToken: [] parameters: - $ref: '#/components/parameters/ProjectId' + - $ref: '#/components/parameters/FrontendId' requestBody: required: true content: @@ -7666,51 +9757,27 @@ paths: 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. + 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 directory or monorepo workspace root. The API enforces SOURCE_ARCHIVE_SIZE_LIMIT_MB and stores a normalized tar.gz archive. + 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: 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 + '202': + description: Candidate created; its first deployment is running content: application/json: schema: - $ref: '#/components/schemas/Frontend' + $ref: '#/components/schemas/FrontendCandidate' '400': - description: Bad request + 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: @@ -7722,19 +9789,31 @@ paths: schema: $ref: '#/components/schemas/Error' '403': - description: Frontend deployment limit exceeded for the current plan or project hard cap + description: Forbidden - project ownership required content: application/json: schema: $ref: '#/components/schemas/Error' '404': - description: Project not found + description: Frontend not found, or the `frontends.candidates` capability is unavailable (code `feature_unavailable`) content: application/json: schema: $ref: '#/components/schemas/Error' '409': - description: Conflict - frontend deletion is queued or running + 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: @@ -7746,30 +9825,31 @@ paths: schema: $ref: '#/components/schemas/Error' '503': - description: Service unavailable - frontend workflow or archive limit configuration missing + description: Service unavailable - frontend deployments are not configured content: application/json: schema: $ref: '#/components/schemas/Error' - /projects/{id}/frontends/{frontendId}: + /projects/{id}/frontends/{frontendId}/candidates/{candidateId}: get: tags: - Frontends - summary: Get frontend details - operationId: getFrontend + summary: Get a frontend Candidate + operationId: getFrontendCandidate security: - UserToken: [] - ProjectAccessToken: [] parameters: - $ref: '#/components/parameters/ProjectId' - $ref: '#/components/parameters/FrontendId' + - $ref: '#/components/parameters/FrontendCandidateId' responses: '200': - description: Successful response + description: The Candidate with its latest deployment content: application/json: schema: - $ref: '#/components/schemas/Frontend' + $ref: '#/components/schemas/FrontendCandidate' '400': description: Bad request - invalid identifier content: @@ -7789,7 +9869,7 @@ paths: schema: $ref: '#/components/schemas/Error' '404': - description: Frontend not found + description: Frontend or Candidate not found content: application/json: schema: @@ -7803,22 +9883,26 @@ paths: delete: tags: - Frontends - summary: Delete a frontend + summary: Delete a frontend Candidate 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 + 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/FrontendId' + - $ref: '#/components/parameters/FrontendCandidateId' responses: '202': - description: Frontend deletion started or queued + description: Deletion started '400': description: Bad request - invalid identifier content: @@ -7838,52 +9922,64 @@ paths: schema: $ref: '#/components/schemas/Error' '404': - description: Frontend not found + description: Frontend or Candidate not found content: application/json: schema: $ref: '#/components/schemas/Error' - '500': - description: Internal server error + '409': + description: '`code: candidate_in_use` - the frontend serves this Candidate.' content: application/json: schema: $ref: '#/components/schemas/Error' - '503': - description: Service unavailable - frontend workflow configuration missing + '500': + description: Internal server error content: application/json: schema: $ref: '#/components/schemas/Error' - /projects/{id}/frontends/{frontendId}/redeploy: + /projects/{id}/frontends/{frontendId}/candidates/{candidateId}/deployments: post: tags: - Frontends - summary: Redeploy frontend using latest uploaded artifact + summary: Deploy a new archive to a frontend Candidate 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 + 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' - $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: Frontend redeploy started or queued + '202': + description: The deployment is running content: application/json: schema: - $ref: '#/components/schemas/Frontend' + $ref: '#/components/schemas/FrontendCandidateDeployment' '400': - description: Bad request - invalid identifier + 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: @@ -7901,124 +9997,65 @@ paths: schema: $ref: '#/components/schemas/Error' '404': - description: Frontend 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: 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 - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - /projects/{id}/frontends/{frontendId}/domain: - get: - tags: - - Frontends - summary: Get frontend custom domain status - operationId: getFrontendCustomDomain - security: - - UserToken: [] - - ProjectAccessToken: [] - parameters: - - $ref: '#/components/parameters/ProjectId' - - $ref: '#/components/parameters/FrontendId' - 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 + 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' - '401': - description: Unauthorized - invalid or missing token + '413': + description: The request body is larger than the archive limit, SOURCE_ARCHIVE_SIZE_LIMIT_MB content: application/json: schema: $ref: '#/components/schemas/Error' - '403': - description: Forbidden - project ownership required + '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' - '404': - description: Frontend not found + '500': + description: Internal server error content: application/json: schema: $ref: '#/components/schemas/Error' - '500': - description: Internal server error + '503': + description: Service unavailable - frontend deployments are not configured content: application/json: schema: $ref: '#/components/schemas/Error' - post: + /projects/{id}/frontends/{frontendId}/serving: + get: tags: - Frontends - summary: Configure frontend custom domain + summary: Get what a frontend serves 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 + 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' - $ref: '#/components/parameters/FrontendId' - requestBody: - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/CreateFrontendCustomDomainRequest' 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: What the frontend serves content: application/json: schema: - $ref: '#/components/schemas/FrontendCustomDomainResponse' + $ref: '#/components/schemas/FrontendServing' '400': - description: Bad request - invalid domain + description: Bad request - invalid identifier content: application/json: schema: @@ -8030,56 +10067,70 @@ paths: 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 - 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 + description: Forbidden - project ownership required content: application/json: schema: - $ref: '#/components/schemas/FrontendCustomDomainConflictError' - '500': - description: Internal server error + $ref: '#/components/schemas/Error' + '404': + description: Frontend not found content: application/json: schema: $ref: '#/components/schemas/Error' - '503': - description: Service unavailable - custom domain provisioning is temporarily unavailable + '500': + description: Internal server error content: application/json: schema: $ref: '#/components/schemas/Error' - delete: + /projects/{id}/frontends/{frontendId}/serving/rollback: + post: tags: - Frontends - summary: Delete frontend custom domain - operationId: deleteFrontendCustomDomain + summary: Roll a frontend back to the runtime it served before + description: | + 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. + operationId: rollbackFrontendServing security: - UserToken: [] - ProjectAccessToken: [] parameters: - $ref: '#/components/parameters/ProjectId' - $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: - '204': - description: Custom domain detach scheduled + '200': + description: The frontend serves the runtime it was rolled back to + content: + application/json: + schema: + $ref: '#/components/schemas/FrontendServing' '400': - description: Bad request - invalid identifier + description: Bad request - invalid identifier or body content: application/json: schema: @@ -8097,13 +10148,19 @@ paths: schema: $ref: '#/components/schemas/Error' '404': - description: Frontend or custom domain not found + 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: The custom domain switched TLS mode while the request ran. Send it again. + 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: @@ -8114,29 +10171,56 @@ paths: application/json: schema: $ref: '#/components/schemas/Error' - /projects/{id}/frontends/{frontendId}/deployments: - get: + /projects/{id}/frontends/{frontendId}/candidates/{candidateId}/promote: + post: tags: - Frontends - summary: List frontend deployments - operationId: listFrontendDeployments + summary: Promote a frontend Candidate + description: | + 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. + operationId: promoteFrontendCandidate security: - UserToken: [] - ProjectAccessToken: [] parameters: - $ref: '#/components/parameters/ProjectId' - $ref: '#/components/parameters/FrontendId' - - $ref: '#/components/parameters/Page' - - $ref: '#/components/parameters/Limit' + - $ref: '#/components/parameters/FrontendCandidateId' + requestBody: + required: true + content: + application/json: + schema: + type: object + additionalProperties: false + required: + - expected_revision + properties: + expected_revision: + type: integer + format: int64 + minimum: 0 responses: '200': - description: Successful response + description: The frontend serves the Candidate content: application/json: schema: - $ref: '#/components/schemas/PaginatedFrontendDeployments' + $ref: '#/components/schemas/FrontendServing' '400': - description: Bad request - invalid identifier + description: Bad request - invalid identifier or body content: application/json: schema: @@ -8154,7 +10238,19 @@ paths: schema: $ref: '#/components/schemas/Error' '404': - description: Frontend 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: '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' + '413': + description: The request body is larger than 4 KiB content: application/json: schema: @@ -8290,16 +10386,218 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/CreateFrontendFunctionRouteRequest' + $ref: '#/components/schemas/CreateFrontendFunctionRouteRequest' + responses: + '201': + description: Function route created + content: + application/json: + schema: + $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: 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: 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 create Function route + 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: + 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 + security: + - UserToken: [] + - ProjectAccessToken: [] + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/CreateFrontendFunctionRouteRequest' + responses: + '200': + description: Function route replaced + content: + application/json: + schema: + $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: Project not owned by the caller + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '404': + 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: + - Frontends + summary: Delete a Frontend Function route + operationId: deleteFrontendFunctionRoute + security: + - UserToken: [] + - ProjectAccessToken: [] + responses: + '204': + description: Function route 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: Function route not found on the Frontend + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '500': + description: Failed to delete Function route + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + /projects/{id}/frontends/{frontendId}/frontend-routes: + parameters: + - $ref: '#/components/parameters/ProjectId' + - $ref: '#/components/parameters/FrontendId' + get: + tags: + - Frontends + summary: List a Frontend's Frontend routes + operationId: listFrontendRoutes + security: + - UserToken: [] + - ProjectAccessToken: [] + responses: + '200': + description: Frontend routes ordered from most to least specific + content: + application/json: + schema: + $ref: '#/components/schemas/FrontendRouteList' + '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 Frontend routes + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + post: + tags: + - 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: [] + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/CreateFrontendRouteRequest' responses: '201': - description: Function route created + description: Frontend route created content: application/json: schema: - $ref: '#/components/schemas/FrontendFunctionRoute' + $ref: '#/components/schemas/FrontendRoute' '400': - description: Invalid path or non-HTTP Function + description: Invalid path, or the Frontend would mount itself content: application/json: schema: @@ -8317,34 +10615,34 @@ paths: schema: $ref: '#/components/schemas/Error' '404': - description: Frontend or Function not found in the Project + 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 the Function is not public + 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: Failed to create Function route + description: Failed to create Frontend route content: application/json: schema: $ref: '#/components/schemas/Error' - /projects/{id}/frontends/{frontendId}/function-routes/{routeId}: + /projects/{id}/frontends/{frontendId}/frontend-routes/{routeId}: parameters: - $ref: '#/components/parameters/ProjectId' - $ref: '#/components/parameters/FrontendId' - - $ref: '#/components/parameters/FrontendFunctionRouteId' + - $ref: '#/components/parameters/FrontendRouteId' put: 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 + 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: [] @@ -8353,16 +10651,16 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/CreateFrontendFunctionRouteRequest' + $ref: '#/components/schemas/CreateFrontendRouteRequest' responses: '200': - description: Function route replaced + description: Frontend route replaced content: application/json: schema: - $ref: '#/components/schemas/FrontendFunctionRoute' + $ref: '#/components/schemas/FrontendRoute' '400': - description: Invalid path or non-HTTP Function + description: Invalid path, or the Frontend would mount itself content: application/json: schema: @@ -8380,19 +10678,19 @@ paths: schema: $ref: '#/components/schemas/Error' '404': - description: Function route, Frontend, or Function 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, the Frontend has reached its 64-route limit, or the Function is not public + 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: Failed to replace Function route + description: Failed to replace Frontend route content: application/json: schema: @@ -8400,14 +10698,14 @@ paths: delete: tags: - Frontends - summary: Delete a Frontend Function route - operationId: deleteFrontendFunctionRoute + summary: Delete a Frontend route + operationId: deleteFrontendRoute security: - UserToken: [] - ProjectAccessToken: [] responses: '204': - description: Function route deleted + description: Frontend route deleted '401': description: Unauthorized content: @@ -8421,13 +10719,13 @@ paths: schema: $ref: '#/components/schemas/Error' '404': - description: Function route not found on the Frontend + description: Frontend route not found on the Frontend content: application/json: schema: $ref: '#/components/schemas/Error' '500': - description: Failed to delete Function route + description: Failed to delete Frontend route content: application/json: schema: @@ -9268,9 +11566,9 @@ paths: 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. operationId: listDatabaseBackups security: - UserToken: [] @@ -9342,7 +11640,7 @@ paths: schema: $ref: '#/components/schemas/DatabaseBackup' '400': - description: Invalid backup name + description: Invalid backup name, or one with a reserved prefix content: application/json: schema: @@ -9686,8 +11984,12 @@ paths: $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. + 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: @@ -9700,13 +12002,16 @@ paths: $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. + 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/Error' + $ref: '#/components/schemas/DatabaseRestoreConflictError' '503': description: Backups are temporarily unavailable content: @@ -9754,6 +12059,321 @@ paths: application/json: schema: $ref: '#/components/schemas/Error' + /projects/{id}/databases/{databaseName}/migrations: + get: + tags: + - Database Migrations + summary: Get a database's migration history + description: | + 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. + operationId: getDatabaseMigrations + security: + - UserToken: [] + - ProjectAccessToken: [] + parameters: + - $ref: '#/components/parameters/ProjectId' + - $ref: '#/components/parameters/DatabaseName' + responses: + '200': + description: Successful response + content: + application/json: + schema: + $ref: '#/components/schemas/DatabaseMigrations' + '404': + description: Project or database not found + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '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' + '503': + description: Volcano could not reach the database + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + /projects/{id}/databases/{databaseName}/migrations/baseline: + post: + tags: + - 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`. + + 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`. + operationId: baselineDatabaseMigrations + security: + - UserToken: [] + - ProjectAccessToken: [] + parameters: + - $ref: '#/components/parameters/ProjectId' + - $ref: '#/components/parameters/DatabaseName' + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/DatabaseMigrationFilesRequest' + responses: + '200': + description: The files are recorded + content: + application/json: + schema: + $ref: '#/components/schemas/DatabaseMigrationBaseline' + '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 or database not found, or migration runs are not available + here (code `feature_unavailable`). + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '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/DatabaseMigrationConflictError' + '413': + description: The request body is larger than 4 MiB + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '503': + description: Volcano could not reach the database + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + /projects/{id}/databases/{databaseName}/migration-runs: + get: + tags: + - Database Migrations + summary: List a database's migration runs + description: | + 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. + operationId: listDatabaseMigrationRuns + security: + - UserToken: [] + - ProjectAccessToken: [] + parameters: + - $ref: '#/components/parameters/ProjectId' + - $ref: '#/components/parameters/DatabaseName' + responses: + '200': + description: Successful response + content: + application/json: + schema: + $ref: '#/components/schemas/DatabaseMigrationRunList' + '404': + description: Project or database not found + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + 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/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 or database not found, or migration runs are not available + here (code `feature_unavailable`). + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '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: + - Database Migrations + summary: Get a migration run + description: | + Returns the run with each file's outcome. Poll this after starting a + run. + + Available whether or not migration runs are. + operationId: getDatabaseMigrationRun + security: + - UserToken: [] + - ProjectAccessToken: [] + parameters: + - $ref: '#/components/parameters/ProjectId' + - $ref: '#/components/parameters/DatabaseName' + - $ref: '#/components/parameters/MigrationRunId' + responses: + '200': + description: Successful response + content: + application/json: + schema: + $ref: '#/components/schemas/DatabaseMigrationRun' + '404': + description: Project, database, or run not found + content: + application/json: + schema: + $ref: '#/components/schemas/Error' /projects/{id}/databases/{databaseName}/reset-password: post: tags: @@ -9860,8 +12480,28 @@ paths: $ref: '#/components/schemas/Database' '400': description: Invalid database type + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '401': + description: Not authenticated + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '403': + description: Access denied or the requested size exceeds the plan allowance (code plan_required) + content: + application/json: + schema: + $ref: '#/components/schemas/Error' '404': description: Database not found + content: + application/json: + schema: + $ref: '#/components/schemas/Error' '409': description: | The database is not active — being provisioned, deleted, or @@ -9870,6 +12510,12 @@ paths: 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 @@ -9990,7 +12636,7 @@ paths: schema: $ref: '#/components/schemas/Error' '403': - description: Access denied + 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: @@ -10013,7 +12659,7 @@ paths: **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 @@ -10068,7 +12714,7 @@ paths: schema: $ref: '#/components/schemas/Error' '403': - description: Access denied + 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: @@ -10142,7 +12788,7 @@ paths: schema: $ref: '#/components/schemas/Error' '403': - description: Access denied + 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: @@ -10215,7 +12861,7 @@ paths: schema: $ref: '#/components/schemas/Error' '403': - description: Access denied + 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: @@ -10284,7 +12930,7 @@ paths: schema: $ref: '#/components/schemas/Error' '403': - description: Access denied + 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: @@ -10347,7 +12993,7 @@ paths: schema: $ref: '#/components/schemas/Error' '403': - description: Access denied + 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: @@ -10372,7 +13018,7 @@ paths: **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 @@ -10432,7 +13078,7 @@ paths: schema: $ref: '#/components/schemas/Error' '403': - description: Access denied + 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: @@ -10513,7 +13159,7 @@ paths: schema: $ref: '#/components/schemas/Error' '403': - description: Access denied + 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: @@ -10593,7 +13239,7 @@ paths: schema: $ref: '#/components/schemas/Error' '403': - description: Access denied + 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: @@ -10669,7 +13315,7 @@ paths: schema: $ref: '#/components/schemas/Error' '403': - description: Access denied + 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: @@ -10983,8 +13629,9 @@ paths: 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. + `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': description: Rate limit exceeded '503': @@ -11046,11 +13693,12 @@ paths: 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. + 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': description: Rate limit exceeded /auth/refresh: @@ -11100,7 +13748,8 @@ paths: $ref: '#/components/schemas/Error' '403': description: | - The account's email domain is not in `allowed_email_domains` while + 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: @@ -11197,7 +13846,7 @@ paths: schema: $ref: '#/components/schemas/Error' '403': - description: Password reset is disabled for this project + description: Password reset or email/password is turned off for this project content: application/json: schema: @@ -11254,6 +13903,12 @@ paths: 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: + application/json: + schema: + $ref: '#/components/schemas/Error' '503': description: Compromised-password screening is temporarily unavailable content: @@ -11445,7 +14100,8 @@ paths: description: Not an anonymous user '403': description: | - The chosen email domain is not in `allowed_email_domains` + 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': @@ -11503,7 +14159,8 @@ paths: $ref: '#/components/schemas/Error' '403': description: | - The requested email domain is not in `allowed_email_domains` + The requested email domain is not in `allowed_email_domains`, or is + reserved (`anonymous.volcano.internal`, `volcano.local`) content: application/json: schema: @@ -11870,8 +14527,14 @@ paths: application/json: schema: $ref: '#/components/schemas/Error' - '401': - description: Not authenticated - access token missing or invalid + '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: @@ -12015,7 +14678,7 @@ paths: schema: $ref: '#/components/schemas/Error' '403': - description: The promoted identity's email domain is not in the project's allowed_email_domains + 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: @@ -12556,7 +15219,7 @@ paths: schema: $ref: '#/components/schemas/EmailTemplate' '400': - description: Invalid template type + description: Invalid template type or subject containing a literal interior carriage return or newline content: application/json: schema: @@ -12641,6 +15304,12 @@ paths: 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: @@ -12702,7 +15371,7 @@ paths: data: type: array items: - $ref: '#/components/schemas/EmailTemplate' + $ref: '#/components/schemas/DefaultEmailTemplate' /email-templates/defaults/{type}: get: tags: @@ -12726,9 +15395,13 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/EmailTemplate' + $ref: '#/components/schemas/DefaultEmailTemplate' '404': description: Template type not found + content: + application/json: + schema: + $ref: '#/components/schemas/Error' /projects/{id}/auth/config: get: tags: @@ -12772,6 +15445,12 @@ paths: 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 @@ -12803,6 +15482,9 @@ paths: 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: [] @@ -12823,7 +15505,7 @@ paths: schema: $ref: '#/components/schemas/TestEmailResponse' '400': - description: Invalid request or email delivery not configured + description: Invalid request, unsafe email headers, or email delivery not configured '401': description: Unauthorized '403': @@ -13806,14 +16488,23 @@ paths: 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) + 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`. + 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: @@ -13859,9 +16550,9 @@ paths: description: Missing or invalid project anon key; or invalid auth proxy metadata '403': 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 + 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 @@ -13959,8 +16650,8 @@ paths: $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 + `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: @@ -14052,9 +16743,9 @@ paths: '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 + 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: @@ -14065,7 +16756,12 @@ paths: tags: - OAuth Authentication summary: List user's linked providers - description: Get list of OAuth providers linked to current user + 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: [] @@ -14081,9 +16777,28 @@ paths: 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 @@ -14183,8 +16898,10 @@ paths: - OAuth Authentication summary: Unlink OAuth provider description: | - 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`). operationId: authUnlinkOAuthProvider security: - AuthUserAccessToken: [] @@ -14565,6 +17282,18 @@ paths: 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: @@ -14655,6 +17384,12 @@ paths: 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: @@ -14686,6 +17421,10 @@ paths: description: Forbidden '404': description: Anon key not found + content: + application/json: + schema: + $ref: '#/components/schemas/Error' '500': description: Internal server error content: @@ -15111,9 +17850,18 @@ paths: 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 @@ -15124,8 +17872,18 @@ paths: 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: @@ -15151,6 +17909,15 @@ paths: 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: @@ -15203,6 +17970,15 @@ paths: 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: @@ -16213,6 +18989,8 @@ paths: 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: @@ -16354,6 +19132,8 @@ paths: 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: @@ -16386,8 +19166,11 @@ paths: | `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 | + | `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` | + | `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 | A capability missing from the list is unavailable, and a capability under another, such as `sandboxes.sessions`, is unavailable whenever its parent is. @@ -16395,7 +19178,13 @@ paths: 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. operationId: listCapabilities security: [] responses: @@ -16415,10 +19204,14 @@ paths: status: unavailable - id: issues status: available - - id: autofix + - id: functions.response_streaming + status: available + - id: frontend_routes status: available - - id: autofix.managed_models + - id: frontends.candidates status: unavailable + - id: databases.migrations + status: available /openapi.json: get: tags: @@ -16814,6 +19607,76 @@ components: 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 @@ -16830,6 +19693,14 @@ components: 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 @@ -16838,6 +19709,23 @@ components: 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 @@ -16886,14 +19774,6 @@ components: 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 @@ -16925,8 +19805,9 @@ components: 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. + 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 @@ -17104,6 +19985,59 @@ components: `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) + LavaflowRunStatusFilter: + name: status + in: query + required: false + schema: + $ref: '#/components/schemas/LavaflowRunStatus' + description: Only runs in this status. ProjectId: name: id in: path @@ -17112,6 +20046,22 @@ components: 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. + ItemProjectIdQuery: + name: project_id + in: query + required: false + schema: + type: string + format: uuid + description: Optional. The item's own project authorizes the read; when given, the item must belong to this project, or it answers like an unknown one. TokenId: name: tokenId in: path @@ -17138,6 +20088,14 @@ components: 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 @@ -17168,6 +20126,18 @@ components: 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 @@ -17227,6 +20197,116 @@ components: 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 @@ -17388,7 +20468,7 @@ components: 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. + 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 @@ -17446,7 +20526,7 @@ components: 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. + 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 @@ -17722,10 +20802,14 @@ components: 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. + 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 @@ -17734,7 +20818,8 @@ components: 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`.' + - 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 @@ -17992,8 +21077,10 @@ components: 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: @@ -18679,7 +21766,9 @@ components: type: string description: | 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. pattern: ^[a-z0-9][a-z0-9_-]{0,62}$ maxLength: 63 example: before_migration @@ -18690,7 +21779,10 @@ components: properties: name: type: string - description: Branch name (must be unique within the parent database) + 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 @@ -18796,7 +21888,7 @@ components: description: Type of email template subject: type: string - description: Email subject line + 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 @@ -18827,6 +21919,22 @@ components: required: - domain - tls + CreateFrontendDomainRequest: + type: object + additionalProperties: false + 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.' + example: www.example.com + tls: + $ref: '#/components/schemas/FrontendCustomDomainTLSConfig' + redirect: + $ref: '#/components/schemas/FrontendCustomDomainRedirectRequest' + required: + - domain + - tls CreateFunctionSchedulerRequest: type: object required: @@ -19216,10 +22324,11 @@ components: enum: - manual - scheduled + - migration description: | - Whether the backup was requested explicitly or produced by the - backup schedule. Only `manual` backups count against the plan's - backup allowance. + 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 @@ -19670,6 +22779,399 @@ components: type: string format: date-time 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, and statements that cannot + run in a transaction, such as `CREATE INDEX CONCURRENTLY`, are not + supported yet; such a file fails with `migration_failed`. + required: + - name + - sql + DatabaseMigrationFilesRequest: + type: object + properties: + files: + type: array + minItems: 1 + maxItems: 1000 + items: + $ref: '#/components/schemas/DatabaseMigrationFile' + required: + - files + DatabaseMigrationHistoryEntry: + type: object + description: One file the database's migration history records. + properties: + name: + type: string + 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: + - 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 + properties: + 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. `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 or its `COMMIT` failed or was cut + short. The file may have committed; the database's history says, + and the next run's plan applies it only if it is not recorded. + 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. + error: + $ref: '#/components/schemas/DatabaseMigrationFileError' + required: + - name + - outcome + DatabaseMigrationFileError: + type: object + description: | + The database's error for a failed file. `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 + minimum: 1 + description: The line of the file the database reported, when known. + required: + - message + DatabaseMigrationWarning: + type: object + description: A condition the run reports that did not stop it. + properties: + code: + type: string + 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 + required: + - 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`, so the run applied nothing further; files it + already applied stay applied. + `locked`: another session held the migration lock, + or a file 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 + database: + $ref: '#/components/schemas/ResourceReference' + status: + type: string + 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 + 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 + 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 + required: + - id + - database + - status + - phase + - source + - warnings + - created_at + - updated_at + DatabaseMigrationRunList: + type: object + properties: + data: + type: array + items: + $ref: '#/components/schemas/DatabaseMigrationRun' + required: + - data DatabaseStats: type: object properties: @@ -19804,6 +23306,35 @@ components: - verification_uri_complete - expires_in - interval + DefaultEmailTemplate: + type: object + description: Built-in email template used when no custom template applies. + properties: + 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: + - type + - subject + - html_body + - text_body EmailTemplate: type: object description: Custom email template @@ -19838,9 +23369,6 @@ components: format: date-time required: - template_type - - subject - - html_body - - text_body Error: type: object properties: @@ -19848,7 +23376,7 @@ components: type: string code: type: string - description: Stable machine-readable error code when a specific recovery path is available. + 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. 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: - error ImportProvider: @@ -20100,6 +23628,7 @@ components: $ref: '#/components/schemas/ProjectImportRunStatus' error_code: type: string + 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 created_at: @@ -20366,27 +23895,21 @@ components: required: - installations GitRepository: - type: object - properties: - id: - type: integer - format: int64 - description: Stable GitHub repository id (repository.id), unchanged by renames. - full_name: - type: string - 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: - - id - - full_name - - default_branch - - private - - is_empty + 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: @@ -20413,16 +23936,48 @@ components: production_branch: 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. + 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: '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 + 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.' @@ -20439,16 +23994,21 @@ components: frontend_app_root: type: string 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: - auto_deploy_enabled - deploy_functions + - apply_migrations - updated_at UpdateProjectGitDeploySettingsRequest: type: object - description: Full replace of a project's Git auto-deploy settings. + description: Full replace of a project's Git auto-deploy settings, except apply_migrations, which keeps its saved value when omitted. properties: auto_deploy_enabled: type: boolean @@ -20460,9 +24020,119 @@ components: 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: - 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: Why a run failed or was skipped. + properties: + code: + type: string + 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 + 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: + 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: The branch the push updated, the project's production branch at the time. + commit_sha: + type: string + 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: + - id + - status + - branch + - commit_sha + - apply_migrations + - migration_runs + - created_at + PaginatedGitDeploymentRuns: + type: object + properties: + data: + type: array + items: + $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 + - limit + - has_more ProjectLockLeaseRequest: type: object additionalProperties: false @@ -20587,6 +24257,14 @@ components: type: string 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: - production_branch ProjectSourceExportSkip: @@ -20623,11 +24301,19 @@ components: properties: production_branch: 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. + 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: + - root_directory ConnectProjectGitRequest: type: object properties: @@ -20652,7 +24338,7 @@ components: 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.' + 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: - connection_id - installation_id @@ -20723,6 +24409,16 @@ components: type: string format: uuid description: Newest queued deployment that will run after the current operation + serving_candidate_id: + type: string + 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: @@ -20747,6 +24443,15 @@ components: 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: date-time @@ -20756,23 +24461,235 @@ components: format: date-time created_at: type: string - format: date-time - updated_at: + format: date-time + updated_at: + type: string + format: date-time + required: + - 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 + format: uuid + frontend_id: + type: string + format: uuid + name: + type: string + maxLength: 128 + status: + type: string + 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 + updated_at: + type: string + format: date-time + required: + - id + - frontend_id + - name + - status + - created_at + - updated_at + FrontendCandidateDeployment: + type: object + additionalProperties: false + properties: + id: + type: string + format: uuid + status: + type: string + 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 + pattern: ^sha256:[0-9a-f]{64}$ + description: Identifies the resolved configuration the deployment was built with. It carries no value. + error_message: + type: string + description: Why a failed deployment failed. + created_at: + type: string + format: date-time + completed_at: + type: string + format: date-time + description: Set once the deployment is no longer provisioning. + required: + - 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: + 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: + - revision + - candidate_id + - previous_candidate_id + FrontendCandidateList: + type: object + additionalProperties: false + properties: + data: + type: array + items: + $ref: '#/components/schemas/FrontendCandidate' + required: + - data + FrontendFunctionRoute: + 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: + type: string + format: date-time + updated_at: + type: string + format: date-time + required: + - id + - project_id + - frontend_id + - function_id + - path_prefix + - strip_prefix + - created_at + - updated_at + FrontendFunctionRouteList: + type: object + additionalProperties: false + properties: + data: + type: array + items: + $ref: '#/components/schemas/FrontendFunctionRoute' + required: + - data + CreateFrontendFunctionRouteRequest: + type: object + additionalProperties: false + properties: + function_id: + type: string + format: uuid + path_prefix: type: string - format: date-time + minLength: 2 + maxLength: 512 + pattern: ^/[^?#\\]*[^/?#\\]$ + strip_prefix: + type: boolean + default: false required: - - id - - project_id - - name - - framework - - status - - deployed_regions - - function_routes - - created_at - - updated_at - FrontendFunctionRoute: + - 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: string @@ -20783,16 +24700,16 @@ components: frontend_id: type: string format: uuid - function_id: + 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: ^/[^?#\\]*[^/?#\\]$ - strip_prefix: - type: boolean created_at: type: string format: date-time @@ -20803,39 +24720,47 @@ components: - id - project_id - frontend_id - - function_id + - target_frontend_id - path_prefix - - strip_prefix - created_at - updated_at - FrontendFunctionRouteList: + FrontendRouteList: type: object additionalProperties: false properties: data: type: array items: - $ref: '#/components/schemas/FrontendFunctionRoute' + $ref: '#/components/schemas/FrontendRoute' required: - data - CreateFrontendFunctionRouteRequest: + CreateFrontendRouteRequest: type: object additionalProperties: false properties: - function_id: + target_frontend_id: type: string format: uuid + description: The Frontend to mount. It must be another Frontend in the Project. path_prefix: type: string minLength: 2 maxLength: 512 pattern: ^/[^?#\\]*[^/?#\\]$ - strip_prefix: - type: boolean - default: false required: - - function_id + - 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: + 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: + - 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`.' @@ -20944,6 +24869,11 @@ components: 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 @@ -20956,8 +24886,67 @@ components: - domain_status - verification_status - effective_urls + - redirect - created_at - updated_at + FrontendCustomDomainList: + type: object + properties: + data: + type: array + items: + $ref: '#/components/schemas/FrontendCustomDomainResponse' + required: + - data + FrontendCustomDomainRedirect: + type: object + properties: + to: + type: string + description: Hostname the domain redirects to. + status: + type: integer + enum: + - 301 + - 302 + - 307 + - 308 + required: + - 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: + to: + type: string + minLength: 1 + maxLength: 253 + description: Hostname of an active domain of the same frontend that serves it. + example: www.example.com + status: + type: integer + 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: + - to + UpdateFrontendCustomDomainRequest: + type: object + additionalProperties: false + properties: + redirect: + allOf: + - $ref: '#/components/schemas/FrontendCustomDomainRedirectRequest' + nullable: true + description: The redirect to set, or null to make the domain serve the frontend. + required: + - redirect FrontendDeployment: type: object properties: @@ -21004,6 +24993,12 @@ components: 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: @@ -21479,11 +25474,18 @@ components: - $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. + `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. @@ -21561,7 +25563,10 @@ components: 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. + 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: - execution_timeout_seconds - retention_days @@ -21591,7 +25596,8 @@ components: 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: type: boolean description: | @@ -21614,9 +25620,11 @@ components: 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`. + 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 - function_id @@ -21923,6 +25931,8 @@ components: initiated_by: type: string 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 @@ -22280,6 +26290,31 @@ components: 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: + - 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: + - succeeded + - failed + description: Outcome of the most recent finished run. Absent before the first. + last_success_at: + type: string + format: date-time + description: When the most recent successful run finished. + last_failure_at: + type: string + format: date-time + description: When the most recent failed run finished. created_at: type: string format: date-time @@ -23216,9 +27251,10 @@ components: 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. + 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 @@ -23286,9 +27322,17 @@ components: 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)`. Omitted without a stack. + 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. Omitted without a stack. status: $ref: '#/components/schemas/IssueStatus' + exception: + type: boolean + 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. Once `true`, it + stays `true`. event_count: type: integer format: int64 @@ -23329,6 +27373,7 @@ components: - resource - title - status + - exception - event_count - first_seen_at - last_seen_at @@ -23371,266 +27416,217 @@ components: $ref: '#/components/schemas/IssueStatus' required: - status - AutofixSettings: + LavaflowAutonomy: + type: string + enum: + - diagnose_only + - open_pr + description: How far LavaFlow goes on its own. `diagnose_only` stops at a diagnosis; `open_pr` also opens a pull request with a fix. LavaFlow never merges. + LavaflowSettings: type: object - additionalProperties: false + description: A project's LavaFlow settings. LavaFlow sends this project's logs and source code to an AI service that Volcano operates. properties: project_id: type: string format: uuid + description: The project the settings belong to. 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: + description: Whether LavaFlow works on the project's issues. Off by default. + autonomy: + $ref: '#/components/schemas/LavaflowAutonomy' + custom_context: 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. + 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. updated_at: type: string format: date-time - description: When the settings were last saved. Absent until the first save. + nullable: true + description: When the settings were last saved, null until they first are. + updated_by: + type: string + nullable: true + description: The user ID of the person who last saved the settings. + 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.' 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: + - autonomy + - custom_context + - system_prompt + - updated_at + - updated_by + - can_update + 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: + project_id: + type: string + format: uuid + description: The project whose settings to change. 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: + autonomy: + $ref: '#/components/schemas/LavaflowAutonomy' + custom_context: 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. + maxLength: 4000 + system_prompt: + type: string + maxLength: 4000 required: - - enabled - AutofixRunStatus: - type: string - enum: - - queued - - running - - succeeded - - 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: + - project_id + LavaflowDayCounts: type: object - additionalProperties: false properties: - kind: - type: string - enum: - - log - - code - - other - x-enum-varnames: - - AutofixEvidenceKindLog - - AutofixEvidenceKindCode - - AutofixEvidenceKindOther - detail: - type: string - location: + date: type: string - description: A file and line, or a log timestamp. Absent when the evidence has none. + 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: - - kind - - detail - AutofixDiagnosis: + - date + - issues_opened + - pull_requests_opened + LavaflowStats: type: object - additionalProperties: false properties: - summary: - type: string - description: One or two sentences on what goes wrong. - root_cause: + project_id: type: string - evidence: - type: array - items: - $ref: '#/components/schemas/AutofixEvidence' - suggested_fix: + format: uuid + description: The project the counts are for. + window_start: type: string - confidence: + format: date + description: The first UTC day in the window. + window_end: 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: + format: date + description: The last UTC day in the window, today. + days: type: array - description: Repository paths a fix would change. + description: One entry per UTC day, oldest first, zeros included. items: - type: string + $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: - - summary - - root_cause - - evidence - - suggested_fix - - confidence - - fixable - - files - AutofixRunUsage: + - project_id + - window_start + - window_end + - days + - totals + LavaflowResourceReference: type: object - additionalProperties: false - description: Model tokens the run used across every attempt. + description: The function, durable function or frontend an issue came from. properties: - input_tokens: - type: integer - format: int64 - output_tokens: - type: integer - format: int64 - cache_read_input_tokens: - type: integer - format: int64 - cache_creation_input_tokens: - type: integer - format: int64 + type: + type: string + enum: + - function + - durable_function + - frontend + id: + type: string + format: uuid + name: + type: string required: - - input_tokens - - output_tokens - - cache_read_input_tokens - - cache_creation_input_tokens - AutofixEdit: + - type + - id + - name + LavaflowAnomaly: type: object - additionalProperties: false - description: One exact text replacement. An empty `old_text` creates the file. properties: - path: + flagged: + type: boolean + reason: type: string - old_text: + nullable: true + description: Why the resource is flagged, null when it is not. + required: + - flagged + - reason + LavaflowResource: + type: object + properties: + project_id: type: string - new_text: + 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: - - path - - old_text - - new_text - AutofixPatch: + - project_id + - resource + - last_analyzed_at + - issues_opened + - pull_requests_opened + - anomaly + LavaflowResourceList: 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: - title: - type: string - edits: + data: type: array items: - $ref: '#/components/schemas/AutofixEdit' + $ref: '#/components/schemas/LavaflowResource' required: - - title - - edits - AutofixPullRequestState: + - data + LavaflowRunStatus: type: string enum: - - open - - merged - - closed - x-enum-varnames: - - AutofixPullRequestStateOpen - - AutofixPullRequestStateMerged - - AutofixPullRequestStateClosed - AutofixPullRequest: + - 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 - additionalProperties: false - description: The draft pull request the run opened on the connected repository. properties: number: type: integer @@ -23638,48 +27634,24 @@ components: 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: + enum: + - open + - merged + - closed + opened_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. + nullable: true + description: When the run opened the pull request, null for one opened before LavaFlow recorded the time. 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: + - opened_at + LavaflowRunSummary: type: object - additionalProperties: false properties: id: type: string @@ -23687,66 +27659,136 @@ components: project_id: type: string format: uuid + description: The project the run belongs to. + status: + $ref: '#/components/schemas/LavaflowRunStatus' + resource: + $ref: '#/components/schemas/LavaflowResourceReference' issue_id: type: string format: uuid - trigger: - $ref: '#/components/schemas/AutofixRunTrigger' - 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: - 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: - 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: + title: type: string - usage: - $ref: '#/components/schemas/AutofixRunUsage' + nullable: true + description: The title of the fix the run proposed, or its diagnosis' summary. Null while neither is known. created_at: type: string format: date-time - started_at: - type: string - format: date-time - completed_at: + finished_at: type: string format: date-time + nullable: true + pull_request: + allOf: + - $ref: '#/components/schemas/LavaflowPullRequest' + nullable: true required: - id - project_id - - issue_id - - trigger - status - - max_stage - - provider - - model - - usage + - resource + - issue_id + - title - created_at - PaginatedAutofixRuns: + - finished_at + - pull_request + LavaflowLogLine: + type: object + properties: + timestamp: + type: string + format: date-time + nullable: true + level: + type: string + message: + type: string + required: + - timestamp + - level + - message + LavaflowDiagnosis: + type: object + properties: + summary: + type: string + root_cause: + type: string + evidence: + type: array + items: + type: string + log_lines: + type: array + items: + $ref: '#/components/schemas/LavaflowLogLine' + required: + - summary + - root_cause + - evidence + - log_lines + LavaflowReview: + type: object + properties: + 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. + rounds: + type: integer + required: + - verdict + - rounds + LavaflowFailure: + type: object + properties: + code: + type: string + description: Stable code, such as `timed_out` or `feature_paused`. + message: + type: string + description: Fixed text for the code. + required: + - code + - message + LavaflowRun: + allOf: + - $ref: '#/components/schemas/LavaflowRunSummary' + - type: object + properties: + diagnosis: + allOf: + - $ref: '#/components/schemas/LavaflowDiagnosis' + nullable: true + diff: + type: string + nullable: true + description: The fix as a unified diff. Null for now; a run that opened a pull request links to the change in `pull_request`. + review: + allOf: + - $ref: '#/components/schemas/LavaflowReview' + nullable: true + failure: + allOf: + - $ref: '#/components/schemas/LavaflowFailure' + nullable: true + description: Why the run stopped or waits, null when nothing went wrong. + required: + - diagnosis + - diff + - review + - failure + PaginatedLavaflowRuns: type: object properties: data: type: array items: - $ref: '#/components/schemas/AutofixRun' + $ref: '#/components/schemas/LavaflowRunSummary' limit: type: integer description: Number of items per page @@ -23755,11 +27797,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 +28206,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: @@ -24270,8 +28371,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 @@ -24520,6 +28623,43 @@ components: $ref: '#/components/schemas/ProjectConfigFrontendCustomDomainTLSConfig' required: - 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 +28708,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 +28739,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 +28759,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 +29004,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 @@ -25539,7 +29696,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 +30020,7 @@ components: to_email: type: string format: email + x-go-type: string description: Recipient address for the diagnostic email. subject: type: string @@ -25997,8 +30156,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 +30176,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 +30253,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: @@ -26404,6 +30569,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 +30596,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 +30775,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 @@ -26879,6 +31116,112 @@ 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 + 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` when Volcano confirmed, through the project''s GitHub connection, that `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 frontend uploads are checked; a function deployment''s commit, one the client reports dirty, and one from another branch, repository, or a project without a connection, is recorded unverified.' + required: + - repository + - sha + - dirty + - verified DurableMessageWaitStatus: type: string enum: @@ -26927,8 +31270,12 @@ 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 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/list_autofix_runs.py b/src/volcano_sdk/_generated/api/autofix/list_autofix_runs.py deleted file mode 100644 index 0d90897a..00000000 --- a/src/volcano_sdk/_generated/api/autofix/list_autofix_runs.py +++ /dev/null @@ -1,294 +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_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 ...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, - issue_id: UUID | str | Unset = UNSET, - status: AutofixRunStatus | Unset = UNSET, - -) -> dict[str, Any]: - - - - - params: dict[str, Any] = {} - - params["limit"] = limit - - params["cursor"] = cursor - - 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_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": "/projects/{id}/autofix-runs".format(id=quote(str(id), safe=""),), - "params": params, - } - - - return _kwargs - - - -def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Error | PaginatedAutofixRuns | None: - if response.status_code == 200: - response_200 = PaginatedAutofixRuns.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 == 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[Error | PaginatedAutofixRuns]: - 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, - 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. - - Project access tokens can list runs, including read-only ones. - - Args: - id (UUID): - 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] - """ - - - kwargs = request_kwargs( - id=id, -limit=limit, -cursor=cursor, -issue_id=issue_id, -status=status, - - ) - - 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, - 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. - - Project access tokens can list runs, including read-only ones. - - Args: - id (UUID): - 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 - """ - - - return sync_detailed( - id=id, -client=client, -limit=limit, -cursor=cursor, -issue_id=issue_id, -status=status, - - ).parsed - -async def asyncio_detailed( - id: UUID | str, - *, - client: AuthenticatedClient, - 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. - - Project access tokens can list runs, including read-only ones. - - Args: - id (UUID): - 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] - """ - - - kwargs = request_kwargs( - id=id, -limit=limit, -cursor=cursor, -issue_id=issue_id, -status=status, - - ) - - 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, - 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. - - Project access tokens can list runs, including read-only ones. - - Args: - id (UUID): - 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 - """ - - - return (await asyncio_detailed( - id=id, -client=client, -limit=limit, -cursor=cursor, -issue_id=issue_id, -status=status, - - )).parsed 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/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/frontends/create_frontend.py b/src/volcano_sdk/_generated/api/frontends/create_frontend.py index 1509d39f..8c6bf8e4 100644 --- a/src/volcano_sdk/_generated/api/frontends/create_frontend.py +++ b/src/volcano_sdk/_generated/api/frontends/create_frontend.py @@ -153,12 +153,12 @@ def sync_detailed( `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`). + 16.4.3 (`>=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: @@ -217,12 +217,12 @@ def sync( `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`). + 16.4.3 (`>=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: @@ -276,12 +276,12 @@ async def asyncio_detailed( `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`). + 16.4.3 (`>=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: @@ -340,12 +340,12 @@ async def asyncio( `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`). + 16.4.3 (`>=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/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/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/get_lavaflow_run.py b/src/volcano_sdk/_generated/api/lava_flow/get_lavaflow_run.py new file mode 100644 index 00000000..57cdaade --- /dev/null +++ b/src/volcano_sdk/_generated/api/lava_flow/get_lavaflow_run.py @@ -0,0 +1,246 @@ +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 and + its review. 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. + + 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 and + its review. 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. + + 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 and + its review. 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. + + 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 and + its review. 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. + + 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_stats.py b/src/volcano_sdk/_generated/api/lava_flow/get_lavaflow_stats.py new file mode 100644 index 00000000..9237b76b --- /dev/null +++ b/src/volcano_sdk/_generated/api/lava_flow/get_lavaflow_stats.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.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, + +) -> dict[str, Any]: + + + + + params: dict[str, Any] = {} + + 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": "/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, + +) -> 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 and `days`. + + Args: + project_id (UUID): + 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 | LavaflowStats] + """ + + + kwargs = request_kwargs( + project_id=project_id, +days=days, + + ) + + 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, + +) -> 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 and `days`. + + Args: + project_id (UUID): + 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 | LavaflowStats + """ + + + return sync_detailed( + client=client, +project_id=project_id, +days=days, + + ).parsed + +async def asyncio_detailed( + *, + client: AuthenticatedClient, + project_id: UUID | str, + days: int | Unset = 30, + +) -> 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 and `days`. + + Args: + project_id (UUID): + 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 | LavaflowStats] + """ + + + kwargs = request_kwargs( + 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, + project_id: UUID | str, + days: int | Unset = 30, + +) -> 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 and `days`. + + Args: + project_id (UUID): + 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 | LavaflowStats + """ + + + return (await asyncio_detailed( + client=client, +project_id=project_id, +days=days, + + )).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..82a2c90b --- /dev/null +++ b/src/volcano_sdk/_generated/api/lava_flow/list_lavaflow_resources.py @@ -0,0 +1,262 @@ +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 ...types import UNSET, Unset +from typing import cast +from uuid import UUID + + + +def request_kwargs( + *, + project_id: UUID | str, + days: int | Unset = 30, + +) -> dict[str, Any]: + + + + + params: dict[str, Any] = {} + + 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": "/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, + +) -> 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 with activity in the window is listed too, 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. + + Args: + project_id (UUID): + 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 | LavaflowResourceList] + """ + + + kwargs = request_kwargs( + project_id=project_id, +days=days, + + ) + + 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, + +) -> 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 with activity in the window is listed too, 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. + + Args: + project_id (UUID): + 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 | LavaflowResourceList + """ + + + return sync_detailed( + client=client, +project_id=project_id, +days=days, + + ).parsed + +async def asyncio_detailed( + *, + client: AuthenticatedClient, + project_id: UUID | str, + days: int | Unset = 30, + +) -> 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 with activity in the window is listed too, 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. + + Args: + project_id (UUID): + 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 | LavaflowResourceList] + """ + + + kwargs = request_kwargs( + 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, + project_id: UUID | str, + days: int | Unset = 30, + +) -> 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 with activity in the window is listed too, 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. + + Args: + project_id (UUID): + 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 | LavaflowResourceList + """ + + + return (await asyncio_detailed( + client=client, +project_id=project_id, +days=days, + + )).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..0f4c0ddc --- /dev/null +++ b/src/volcano_sdk/_generated/api/lava_flow/list_lavaflow_runs.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.error import Error +from ...models.lavaflow_run_status import check_lavaflow_run_status +from ...models.lavaflow_run_status import LavaflowRunStatus +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, + +) -> 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 + + + 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, + +) -> Response[Error | PaginatedLavaflowRuns]: + """ List LavaFlow runs + + Pages the project's LavaFlow runs, newest first. A page carries no run + text; read a run for its diagnosis, log lines and diff. + + 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): + + Raises: + errors.UnexpectedStatus: If the server 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, + + ) + + 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, + +) -> Error | PaginatedLavaflowRuns | None: + """ List LavaFlow runs + + Pages the project's LavaFlow runs, newest first. A page carries no run + text; read a run for its diagnosis, log lines and diff. + + 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): + + Raises: + errors.UnexpectedStatus: If the server 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, + + ).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, + +) -> Response[Error | PaginatedLavaflowRuns]: + """ List LavaFlow runs + + Pages the project's LavaFlow runs, newest first. A page carries no run + text; read a run for its diagnosis, log lines and diff. + + 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): + + Raises: + errors.UnexpectedStatus: If the server 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, + + ) + + 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, + +) -> Error | PaginatedLavaflowRuns | None: + """ List LavaFlow runs + + Pages the project's LavaFlow runs, newest first. A page carries no run + text; read a run for its diagnosis, log lines and diff. + + 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): + + Raises: + errors.UnexpectedStatus: If the server 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, + + )).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..a1e0a2e7 --- /dev/null +++ b/src/volcano_sdk/_generated/api/lava_flow/update_lavaflow_settings.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_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 == 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. LavaFlow sends this project's logs and source code to an AI + service that Volcano operates. + + Only the project's owner can save, with a platform token, while their + account is active. A full-scope project access token gets `403` with + code `person_required`; a read-only one is refused as read-only first, + without a code, and so is the owner of a read-only account. + + 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 off, + sending `enabled: false` and nothing else to change. 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. LavaFlow sends this project's logs and source code to an AI + service that Volcano operates. + + Only the project's owner can save, with a platform token, while their + account is active. A full-scope project access token gets `403` with + code `person_required`; a read-only one is refused as read-only first, + without a code, and so is the owner of a read-only account. + + 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 off, + sending `enabled: false` and nothing else to change. 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. LavaFlow sends this project's logs and source code to an AI + service that Volcano operates. + + Only the project's owner can save, with a platform token, while their + account is active. A full-scope project access token gets `403` with + code `person_required`; a read-only one is refused as read-only first, + without a code, and so is the owner of a read-only account. + + 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 off, + sending `enabled: false` and nothing else to change. 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. LavaFlow sends this project's logs and source code to an AI + service that Volcano operates. + + Only the project's owner can save, with a platform token, while their + account is active. A full-scope project access token gets `403` with + code `person_required`; a read-only one is refused as read-only first, + without a code, and so is the owner of a read-only account. + + 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 off, + sending `enabled: false` and nothing else to change. 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/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..d9be6dde 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,19 @@ 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. + Args: id (UUID): body (ConnectProjectGitRequest): @@ -176,6 +189,19 @@ 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. + Args: id (UUID): body (ConnectProjectGitRequest): @@ -214,6 +240,19 @@ 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. + Args: id (UUID): body (ConnectProjectGitRequest): @@ -257,6 +296,19 @@ 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. + 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..3c78f7ad --- /dev/null +++ b/src/volcano_sdk/_generated/api/projects/list_project_capabilities.py @@ -0,0 +1,259 @@ +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 | + + 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 | + + 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 | + + 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 | + + 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/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/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..04341c35 100644 --- a/src/volcano_sdk/_generated/api/system/list_capabilities.py +++ b/src/volcano_sdk/_generated/api/system/list_capabilities.py @@ -72,9 +72,17 @@ def sync_detailed( | `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 | + | `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` | + | `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 | 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 +90,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. @@ -120,9 +134,17 @@ def sync( | `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 | + | `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` | + | `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 | 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 +152,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. @@ -163,9 +191,17 @@ async def asyncio_detailed( | `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 | + | `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` | + | `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 | 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 +209,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. @@ -211,9 +253,17 @@ async def asyncio( | `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 | + | `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` | + | `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 | 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 +271,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..c4171b0a 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 @@ -151,8 +137,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 +180,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 +208,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 +219,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 +228,7 @@ 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_phase import DeploymentPhase from .deployment_phase_name import DeploymentPhaseName from .deployment_phase_status import DeploymentPhaseStatus @@ -270,7 +283,18 @@ from .export_project_source_request import ExportProjectSourceRequest from .fail_durable_callback_request import FailDurableCallbackRequest 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 +313,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 +339,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 @@ -332,10 +361,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 @@ -350,6 +384,29 @@ from .import_sources_response import ImportSourcesResponse from .issue import Issue from .issue_status import IssueStatus +from .lavaflow_anomaly import LavaflowAnomaly +from .lavaflow_autonomy import LavaflowAutonomy +from .lavaflow_day_counts import LavaflowDayCounts +from .lavaflow_diagnosis import LavaflowDiagnosis +from .lavaflow_failure import LavaflowFailure +from .lavaflow_log_line import LavaflowLogLine +from .lavaflow_pull_request import LavaflowPullRequest +from .lavaflow_pull_request_state import LavaflowPullRequestState +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_verdict import LavaflowReviewVerdict +from .lavaflow_run import LavaflowRun +from .lavaflow_run_status import LavaflowRunStatus +from .lavaflow_run_summary import LavaflowRunSummary +from .lavaflow_settings import LavaflowSettings +from .lavaflow_settings_update import LavaflowSettingsUpdate +from .lavaflow_stats import LavaflowStats +from .lavaflow_stats_totals import LavaflowStatsTotals +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 @@ -397,13 +454,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,7 +475,9 @@ 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_project_access_tokens import PaginatedProjectAccessTokens from .paginated_project_custom_domains import PaginatedProjectCustomDomains from .paginated_project_deployments import PaginatedProjectDeployments @@ -455,26 +520,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 +571,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 @@ -556,6 +628,7 @@ from .project_template_installation_phase import ProjectTemplateInstallationPhase 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 +636,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 +650,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 @@ -605,9 +680,12 @@ 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 .start_git_connect_provider import StartGitConnectProvider from .storage_bucket import StorageBucket from .storage_copy_request import StorageCopyRequest @@ -632,23 +710,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 +750,9 @@ from .verify_domain_request import VerifyDomainRequest __all__ = ( + "AccountSession", + "AccountSessionKind", + "AccountSessionList", "AnonKey", "AuthCancelEmailChangeResponse200", "AuthConfig", @@ -758,23 +843,6 @@ "AuthUserAppMetadata", "AuthUserStatus", "AuthUserUserMetadata", - "AutofixDiagnosis", - "AutofixDiagnosisConfidence", - "AutofixEdit", - "AutofixEvidence", - "AutofixEvidenceKind", - "AutofixModel", - "AutofixPatch", - "AutofixProvider", - "AutofixPullRequest", - "AutofixPullRequestSkipped", - "AutofixPullRequestState", - "AutofixRun", - "AutofixRunStatus", - "AutofixRunTrigger", - "AutofixRunUsage", - "AutofixSettings", - "AutofixStage", "BanAuthUserBody", "BanUserResponse", "BanUserResponseStatus", @@ -820,8 +888,12 @@ "CreateFrontendBody", "CreateFrontendBodyFramework", "CreateFrontendBodyVariableScope", + "CreateFrontendCandidateBody", "CreateFrontendCustomDomainRequest", + "CreateFrontendDeploymentRequest", + "CreateFrontendDomainRequest", "CreateFrontendFunctionRouteRequest", + "CreateFrontendRouteRequest", "CreateFunctionBody", "CreateFunctionBodyRuntime", "CreateFunctionBodyVariableScope", @@ -858,6 +930,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 +958,7 @@ "DatabaseQueryResult", "DatabaseQueryResultDataItem", "DatabaseRestore", + "DatabaseRestoreConflictError", "DatabaseRestoreKind", "DatabaseRestoreList", "DatabaseRestoreStatus", @@ -877,11 +969,14 @@ "DatabaseStatus", "DatabaseUpdateRequest", "DatabaseUpdateRequestValues", + "DefaultEmailTemplate", + "DefaultEmailTemplateType", "DeleteDatabaseBackupResponse200", "DeleteDatabaseBranchResponse202", "DeleteDatabaseResponse202", "DeleteEmailTemplateType", "DeleteOAuthConfigProvider", + "DeploymentCommit", "DeploymentPhase", "DeploymentPhaseName", "DeploymentPhaseStatus", @@ -938,7 +1033,18 @@ "ExportProjectSourceRequest", "FailDurableCallbackRequest", "Frontend", + "FrontendCandidate", + "FrontendCandidateConfigurationStatus", + "FrontendCandidateDeployment", + "FrontendCandidateDeploymentStatus", + "FrontendCandidateList", + "FrontendCandidateStatus", "FrontendCustomDomainConflictError", + "FrontendCustomDomainList", + "FrontendCustomDomainRedirect", + "FrontendCustomDomainRedirectRequest", + "FrontendCustomDomainRedirectRequestStatus", + "FrontendCustomDomainRedirectStatus", "FrontendCustomDomainResponse", "FrontendCustomDomainResponseDomainStatus", "FrontendCustomDomainResponseServingCertificate", @@ -957,6 +1063,9 @@ "FrontendFramework", "FrontendFunctionRoute", "FrontendFunctionRouteList", + "FrontendRoute", + "FrontendRouteList", + "FrontendServing", "FrontendStatus", "FrontendUsageDailyEntry", "FrontendUsageData", @@ -980,6 +1089,8 @@ "FunctionRuntimeOption", "FunctionRuntimesResponse", "FunctionScheduler", + "FunctionSchedulerHealth", + "FunctionSchedulerLastRunStatus", "FunctionSchedulerListResponse", "FunctionSchedulerPayload", "FunctionSchedulerScheduleKind", @@ -1000,10 +1111,15 @@ "GitConnection", "GitConnectionsResponse", "GitConnectStartResponse", + "GitDeploymentMigrationRun", + "GitDeploymentRun", + "GitDeploymentRunError", + "GitDeploymentRunStatus", "GitInstallation", "GitInstallationsResponse", "GitRepositoriesResponse", "GitRepository", + "GitRepositoryReference", "HeartbeatDurableCallbackRequest", "HostedAuthPageType", "HostedLoginEmailCheckRequest", @@ -1018,6 +1134,29 @@ "ImportSourcesResponse", "Issue", "IssueStatus", + "LavaflowAnomaly", + "LavaflowAutonomy", + "LavaflowDayCounts", + "LavaflowDiagnosis", + "LavaflowFailure", + "LavaflowLogLine", + "LavaflowPullRequest", + "LavaflowPullRequestState", + "LavaflowResource", + "LavaflowResourceList", + "LavaflowResourceReference", + "LavaflowResourceReferenceType", + "LavaflowReview", + "LavaflowReviewVerdict", + "LavaflowRun", + "LavaflowRunStatus", + "LavaflowRunSummary", + "LavaflowSettings", + "LavaflowSettingsUpdate", + "LavaflowStats", + "LavaflowStatsTotals", + "ListAccountSessionsSort", + "ListAccountSessionsStatus", "ListAnonKeysResponse200", "ListAuthUsersStatus", "ListAvailableOAuthProvidersResponse200", @@ -1065,13 +1204,19 @@ "ManagedProjectConfigFrontendCustomDomainTLSConfig", "ManagedProjectConfigFrontendCustomDomainTLSConfigMode", "MetricUsageData", + "NotificationEmailSettings", + "NotificationEmailStatus", + "NotificationSettings", + "NotificationTestDelivery", + "NotificationTestDeliveryChannel", + "NotificationTestResult", + "NotificationWebhookSettings", "OAuthConfig", "OAuthConfigProvider", "OAuthErrorResponse", "OpenAPISpecDocument", "OpenDurableMessageSessionRequest", "PaginatedAuthUsers", - "PaginatedAutofixRuns", "PaginatedDatabases", "PaginatedDurableApprovals", "PaginatedDurableExecutions", @@ -1080,7 +1225,9 @@ "PaginatedFrontends", "PaginatedFunctionDeployments", "PaginatedFunctions", + "PaginatedGitDeploymentRuns", "PaginatedIssues", + "PaginatedLavaflowRuns", "PaginatedProjectAccessTokens", "PaginatedProjectCustomDomains", "PaginatedProjectDeployments", @@ -1123,26 +1270,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 +1321,8 @@ "ProjectGitConnection", "ProjectGitConnectionSummary", "ProjectGitDeploySettings", + "ProjectGitOwnerPush", + "ProjectGitOwnerPushReason", "ProjectHealthCategory", "ProjectHealthCheck", "ProjectHealthDataStatus", @@ -1224,6 +1378,7 @@ "ProjectTemplateInstallationPhase", "ProjectTemplateInstallationStatus", "ProjectUsageResponse", + "PromoteFrontendCandidateBody", "PublishDurableMessageRequest", "PublishSandboxPresetRequest", "PublishSandboxPresetRequestMemoryMb", @@ -1231,6 +1386,7 @@ "RealtimeConfig", "RealtimePlanLimits", "RealtimeStats", + "RedeployFrontendCandidateBody", "RefreshOAuthProviderTokenProvider", "RefreshOAuthProviderTokenResponse200", "RegisterDurableCallbackRequest", @@ -1244,6 +1400,7 @@ "ResolveFunctionResponse", "ResourceReference", "ResourceReferenceType", + "RollbackFrontendServingBody", "SandboxAccess", "SandboxAccessRequest", "SandboxBuildLogPage", @@ -1273,9 +1430,12 @@ "SandboxTemplateStatus", "ScheduleRequest", "ScheduleRequestKind", + "SchedulerFailureAlertPolicy", + "SchedulerFailureNotifyOn", "SendDurableMessageRequest", "ServiceKey", "SetProjectGitProductionBranchRequest", + "SetProjectGitRootDirectoryRequest", "StartGitConnectProvider", "StorageBucket", "StorageCopyRequest", @@ -1300,23 +1460,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..181a7354 100644 --- a/src/volcano_sdk/_generated/models/auth_config.py +++ b/src/volcano_sdk/_generated/models/auth_config.py @@ -89,8 +89,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): 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/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..f700ec5c 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,13 @@ 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`. """ name: str @@ -76,6 +83,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 +114,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 +134,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 +180,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 +237,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 +248,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..5df84b0b 100644 --- a/src/volcano_sdk/_generated/models/create_function_body.py +++ b/src/volcano_sdk/_generated/models/create_function_body.py @@ -46,6 +46,8 @@ 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: @@ -80,6 +82,13 @@ 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`. """ name: str @@ -93,6 +102,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 +145,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 +171,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 +232,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 +311,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 +325,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_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..4972e96f --- /dev/null +++ b/src/volcano_sdk/_generated/models/database_migration_conflict_error.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 ..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. 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..b20f49ea --- /dev/null +++ b/src/volcano_sdk/_generated/models/database_migration_file.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 + + + + + + + +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, and statements that cannot + run in a transaction, such as `CREATE INDEX CONCURRENTLY`, are not + supported yet; such a file fails with `migration_failed`. + """ + + 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..16144334 --- /dev/null +++ b/src/volcano_sdk/_generated/models/database_migration_file_error.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 ..types import UNSET, Unset + + + + + + +T = TypeVar("T", bound="DatabaseMigrationFileError") + + + +@_attrs_define +class DatabaseMigrationFileError: + """ The database's error for a failed file. `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..a3efd7c9 --- /dev/null +++ b/src/volcano_sdk/_generated/models/database_migration_run_error.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 ..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`, so the run applied nothing further; files it + already applied stay applied. + `locked`: another session held the migration lock, + or a file 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..80b84ccf --- /dev/null +++ b/src/volcano_sdk/_generated/models/database_migration_run_file.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.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. `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 or its `COMMIT` failed or was cut + short. The file may have committed; the database's history says, + and the next run's plan applies it only if it is not recorded. + 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. + error (DatabaseMigrationFileError | Unset): The database's error for a failed file. `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..19e0f4e2 --- /dev/null +++ b/src/volcano_sdk/_generated/models/database_restore_conflict_error.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 ..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. 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..33c158d9 --- /dev/null +++ b/src/volcano_sdk/_generated/models/deployment_commit.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 + + + + + + + +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` when Volcano confirmed, through the project's GitHub connection, that `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 + frontend uploads are checked; a function deployment's commit, one the client reports dirty, and one from another + branch, repository, or a project without a connection, is recorded unverified. + """ + + repository: str + sha: str + dirty: bool + verified: bool + 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 + + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({ + "repository": repository, + "sha": sha, + "dirty": dirty, + "verified": verified, + }) + + 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") + + deployment_commit = cls( + repository=repository, + sha=sha, + dirty=dirty, + verified=verified, + ) + + + 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/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..86d2d379 100644 --- a/src/volcano_sdk/_generated/models/error.py +++ b/src/volcano_sdk/_generated/models/error.py @@ -25,6 +25,11 @@ 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. 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/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..b06eeba6 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,11 @@ 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. 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_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/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..fad32833 100644 --- a/src/volcano_sdk/_generated/models/issue.py +++ b/src/volcano_sdk/_generated/models/issue.py @@ -38,14 +38,20 @@ class Issue: URLs replaced by placeholders like `` and ``. status (IssueStatus): `open` until someone resolves or ignores the issue. A resolved issue seen again reopens. + 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. 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. Omitted without a stack. 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 +64,7 @@ class Issue: resource: ResourceReference title: str status: IssueStatus + exception: bool event_count: int first_seen_at: datetime.datetime last_seen_at: datetime.datetime @@ -88,6 +95,8 @@ def to_dict(self) -> dict[str, Any]: status: str = self.status + exception = self.exception + event_count = self.event_count first_seen_at = self.first_seen_at.isoformat() @@ -127,6 +136,7 @@ def to_dict(self) -> dict[str, Any]: "resource": resource, "title": title, "status": status, + "exception": exception, "event_count": event_count, "first_seen_at": first_seen_at, "last_seen_at": last_seen_at, @@ -178,6 +188,8 @@ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + exception = d.pop("exception") + event_count = d.pop("event_count") first_seen_at = datetime.datetime.fromisoformat(d.pop("first_seen_at")) @@ -244,6 +256,7 @@ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: resource=resource, title=title, status=status, + exception=exception, event_count=event_count, first_seen_at=first_seen_at, last_seen_at=last_seen_at, 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..9faf8b7a --- /dev/null +++ b/src/volcano_sdk/_generated/models/lavaflow_autonomy.py @@ -0,0 +1,10 @@ +from typing import Literal + +LavaflowAutonomy = Literal['diagnose_only', 'open_pr'] + +LAVAFLOW_AUTONOMY_VALUES: set[LavaflowAutonomy] = { 'diagnose_only', '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_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..109fef1f --- /dev/null +++ b/src/volcano_sdk/_generated/models/lavaflow_diagnosis.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 typing import cast + +if TYPE_CHECKING: + from ..models.lavaflow_log_line import LavaflowLogLine + + + + + +T = TypeVar("T", bound="LavaflowDiagnosis") + + + +@_attrs_define +class LavaflowDiagnosis: + """ + Attributes: + summary (str): + root_cause (str): + evidence (list[str]): + log_lines (list[LavaflowLogLine]): + """ + + 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_failure.py b/src/volcano_sdk/_generated/models/lavaflow_failure.py new file mode 100644 index 00000000..bd428b79 --- /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): Fixed text 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_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_pull_request.py b/src/volcano_sdk/_generated/models/lavaflow_pull_request.py new file mode 100644 index 00000000..7592d584 --- /dev/null +++ b/src/volcano_sdk/_generated/models/lavaflow_pull_request.py @@ -0,0 +1,128 @@ +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_pull_request_state import check_lavaflow_pull_request_state +from ..models.lavaflow_pull_request_state import LavaflowPullRequestState +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. + """ + + number: int + url: str + state: LavaflowPullRequestState + opened_at: datetime.datetime | None + 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 + + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({ + "number": number, + "url": url, + "state": state, + "opened_at": opened_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") + + 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")) + + + lavaflow_pull_request = cls( + number=number, + url=url, + state=state, + opened_at=opened_at, + ) + + + 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_resource.py b/src/volcano_sdk/_generated/models/lavaflow_resource.py new file mode 100644 index 00000000..8ed108b6 --- /dev/null +++ b/src/volcano_sdk/_generated/models/lavaflow_resource.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 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): The function, durable function or frontend an issue came from. + 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..2dbd8c37 --- /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: + """ The function, durable function or frontend an issue came from. + + 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..7773473a --- /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'] + +LAVAFLOW_RESOURCE_REFERENCE_TYPE_VALUES: set[LavaflowResourceReferenceType] = { 'durable_function', 'frontend', 'function', } + +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..daf8f71f --- /dev/null +++ b/src/volcano_sdk/_generated/models/lavaflow_review.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 ..models.lavaflow_review_verdict import check_lavaflow_review_verdict +from ..models.lavaflow_review_verdict import LavaflowReviewVerdict +from typing import cast + + + + + + +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. + rounds (int): + """ + + verdict: LavaflowReviewVerdict + rounds: int + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + + + + + def to_dict(self) -> dict[str, Any]: + verdict: str = self.verdict + + rounds = self.rounds + + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({ + "verdict": verdict, + "rounds": rounds, + }) + + return field_dict + + + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + verdict = check_lavaflow_review_verdict(d.pop("verdict")) + + + + + rounds = d.pop("rounds") + + lavaflow_review = cls( + verdict=verdict, + rounds=rounds, + ) + + + 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_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..1b2da660 --- /dev/null +++ b/src/volcano_sdk/_generated/models/lavaflow_run.py @@ -0,0 +1,329 @@ +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_status import check_lavaflow_run_status +from ..models.lavaflow_run_status import LavaflowRunStatus +from typing import cast +from uuid import UUID +import datetime + +if TYPE_CHECKING: + from ..models.lavaflow_diagnosis import LavaflowDiagnosis + from ..models.lavaflow_failure import LavaflowFailure + from ..models.lavaflow_pull_request import LavaflowPullRequest + from ..models.lavaflow_resource_reference import LavaflowResourceReference + from ..models.lavaflow_review import LavaflowReview + + + + + +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): The function, durable function or frontend an issue came from. + issue_id (UUID): + title (None | str): The title of the fix the run proposed, or its diagnosis' summary. Null while neither is + known. + created_at (datetime.datetime): + finished_at (datetime.datetime | None): + pull_request (LavaflowPullRequest | None): + diagnosis (LavaflowDiagnosis | None): + diff (None | str): The fix as a unified diff. Null for now; a run that opened a pull request links to the change + in `pull_request`. + review (LavaflowReview | None): + failure (LavaflowFailure | None): Why the run stopped or waits, null when nothing went wrong. + """ + + 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 + diagnosis: LavaflowDiagnosis | None + diff: None | str + review: LavaflowReview | None + failure: LavaflowFailure | None + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + + + + + def to_dict(self) -> dict[str, Any]: + from ..models.lavaflow_diagnosis import LavaflowDiagnosis # noqa: PLC0415 + from ..models.lavaflow_failure import LavaflowFailure # noqa: PLC0415 + from ..models.lavaflow_pull_request import LavaflowPullRequest # noqa: PLC0415 + from ..models.lavaflow_resource_reference import LavaflowResourceReference # noqa: PLC0415 + from ..models.lavaflow_review import LavaflowReview # 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 + + 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 + + review: dict[str, Any] | None + if isinstance(self.review, LavaflowReview): + review = self.review.to_dict() + else: + review = self.review + + failure: dict[str, Any] | None + if isinstance(self.failure, LavaflowFailure): + failure = self.failure.to_dict() + else: + failure = self.failure + + + 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, + "diagnosis": diagnosis, + "diff": diff, + "review": review, + "failure": failure, + }) + + return field_dict + + + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.lavaflow_diagnosis import LavaflowDiagnosis # noqa: PLC0415 + from ..models.lavaflow_failure import LavaflowFailure # noqa: PLC0415 + from ..models.lavaflow_pull_request import LavaflowPullRequest # noqa: PLC0415 + from ..models.lavaflow_resource_reference import LavaflowResourceReference # noqa: PLC0415 + from ..models.lavaflow_review import LavaflowReview # 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_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_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_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")) + + + 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, + diagnosis=diagnosis, + diff=diff, + review=review, + failure=failure, + ) + + + 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_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_summary.py b/src/volcano_sdk/_generated/models/lavaflow_run_summary.py new file mode 100644 index 00000000..f00a6907 --- /dev/null +++ b/src/volcano_sdk/_generated/models/lavaflow_run_summary.py @@ -0,0 +1,220 @@ +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_status import check_lavaflow_run_status +from ..models.lavaflow_run_status import LavaflowRunStatus +from typing import cast +from uuid import UUID +import datetime + +if TYPE_CHECKING: + from ..models.lavaflow_pull_request import LavaflowPullRequest + from ..models.lavaflow_resource_reference import LavaflowResourceReference + + + + + +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): The function, durable function or frontend an issue came from. + issue_id (UUID): + title (None | str): The title of the fix the run proposed, or its diagnosis' summary. Null while neither is + known. + created_at (datetime.datetime): + finished_at (datetime.datetime | None): + pull_request (LavaflowPullRequest | None): + """ + + 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 + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + + + + + def to_dict(self) -> dict[str, Any]: + from ..models.lavaflow_pull_request import LavaflowPullRequest # noqa: PLC0415 + from ..models.lavaflow_resource_reference import LavaflowResourceReference # 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 + + + 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, + }) + + return field_dict + + + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.lavaflow_pull_request import LavaflowPullRequest # noqa: PLC0415 + from ..models.lavaflow_resource_reference import LavaflowResourceReference # 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")) + + + 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, + ) + + + 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_settings.py b/src/volcano_sdk/_generated/models/lavaflow_settings.py new file mode 100644 index 00000000..5ffc980d --- /dev/null +++ b/src/volcano_sdk/_generated/models/lavaflow_settings.py @@ -0,0 +1,176 @@ +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 typing import cast +from uuid import UUID +import datetime + + + + + + +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. LavaFlow never merges. + 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. + updated_at (datetime.datetime | None): When the settings were last saved, null until they first are. + updated_by (None | str): The user ID of the person who last saved the settings. + 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. + """ + + project_id: UUID + enabled: bool + autonomy: LavaflowAutonomy + custom_context: str + system_prompt: str + updated_at: datetime.datetime | None + updated_by: None | str + can_update: bool + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + + + + + def to_dict(self) -> dict[str, Any]: + project_id = str(self.project_id) + + enabled = self.enabled + + autonomy: str = self.autonomy + + custom_context = self.custom_context + + system_prompt = self.system_prompt + + 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 + + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({ + "project_id": project_id, + "enabled": enabled, + "autonomy": autonomy, + "custom_context": custom_context, + "system_prompt": system_prompt, + "updated_at": updated_at, + "updated_by": updated_by, + "can_update": can_update, + }) + + 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") + + autonomy = check_lavaflow_autonomy(d.pop("autonomy")) + + + + + custom_context = d.pop("custom_context") + + system_prompt = d.pop("system_prompt") + + 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") + + lavaflow_settings = cls( + project_id=project_id, + enabled=enabled, + autonomy=autonomy, + custom_context=custom_context, + system_prompt=system_prompt, + updated_at=updated_at, + updated_by=updated_by, + can_update=can_update, + ) + + + 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..4e655b7c --- /dev/null +++ b/src/volcano_sdk/_generated/models/lavaflow_settings_update.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 ..models.lavaflow_autonomy import check_lavaflow_autonomy +from ..models.lavaflow_autonomy import LavaflowAutonomy +from ..types import UNSET, Unset +from typing import cast +from uuid import UUID + + + + + + +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. LavaFlow never merges. + custom_context (str | Unset): + system_prompt (str | Unset): + """ + + project_id: UUID + enabled: bool | Unset = UNSET + autonomy: LavaflowAutonomy | Unset = UNSET + custom_context: str | Unset = UNSET + system_prompt: str | Unset = UNSET + + + + + + def to_dict(self) -> dict[str, Any]: + project_id = str(self.project_id) + + enabled = self.enabled + + autonomy: str | Unset = UNSET + if not isinstance(self.autonomy, Unset): + autonomy = self.autonomy + + + custom_context = self.custom_context + + system_prompt = self.system_prompt + + + 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 custom_context is not UNSET: + field_dict["custom_context"] = custom_context + if system_prompt is not UNSET: + field_dict["system_prompt"] = system_prompt + + 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", UNSET) + + _autonomy = d.pop("autonomy", UNSET) + autonomy: LavaflowAutonomy | Unset + if isinstance(_autonomy, Unset): + autonomy = UNSET + else: + autonomy = check_lavaflow_autonomy(_autonomy) + + + + + custom_context = d.pop("custom_context", UNSET) + + system_prompt = d.pop("system_prompt", UNSET) + + lavaflow_settings_update = cls( + project_id=project_id, + enabled=enabled, + autonomy=autonomy, + custom_context=custom_context, + system_prompt=system_prompt, + ) + + return lavaflow_settings_update + 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/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/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..e2dc0952 --- /dev/null +++ b/src/volcano_sdk/_generated/models/paginated_lavaflow_runs.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_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 and caller. + """ + + data: list[LavaflowRunSummary] + 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_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 + + + 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_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) + + paginated_lavaflow_runs = cls( + data=data, + limit=limit, + has_more=has_more, + next_cursor=next_cursor, + ) + + + 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/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_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_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/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/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/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/update_auth_config_request.py b/src/volcano_sdk/_generated/models/update_auth_config_request.py index 7da93df3..6005b8e4 100644 --- a/src/volcano_sdk/_generated/models/update_auth_config_request.py +++ b/src/volcano_sdk/_generated/models/update_auth_config_request.py @@ -79,17 +79,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. 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_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..7342f8b0 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,7 +21,8 @@ @_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): @@ -29,12 +30,19 @@ class UpdateProjectGitDeploySettingsRequest: frontend_name (str | Unset): Frontend to deploy on push. Omit or empty to deploy no frontend. 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 +58,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 +71,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 +89,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 +