From 44272a16ce5396e51db857e1c224bd055692415f Mon Sep 17 00:00:00 2001 From: scalarbot Date: Fri, 19 Jun 2026 18:01:47 +0000 Subject: [PATCH] feat: scalar-typescript-sdk-python@0.1.9 --- .gitignore | 10 + CHANGELOG.md | 5 + LICENSE | 3 + README.md | 227 +- SECURITY.md | 3 + api.md | 837 ++ openapi.augmented.json | 7841 ++++++++++++++ pyproject.toml | 25 + release-please-config.json | 8 + scalar-sdk.manifest.json | 9519 +++++++++++++++++ src/__init__.py | 86 + src/_base_client.py | 2229 ++++ src/_client.py | 794 ++ src/_compat.py | 226 + src/_constants.py | 14 + src/_event_handler.py | 85 + src/_exceptions.py | 126 + src/_files.py | 173 + src/_models.py | 962 ++ src/_qs.py | 149 + src/_resource.py | 43 + src/_response.py | 832 ++ src/_send_queue.py | 90 + src/_streaming.py | 470 + src/_types.py | 274 + src/_utils/__init__.py | 64 + src/_utils/_compat.py | 45 + src/_utils/_datetime_parse.py | 136 + src/_utils/_json.py | 35 + src/_utils/_logs.py | 25 + src/_utils/_path.py | 127 + src/_utils/_proxy.py | 65 + src/_utils/_reflection.py | 42 + src/_utils/_resources_proxy.py | 24 + src/_utils/_streams.py | 12 + src/_utils/_sync.py | 58 + src/_utils/_transform.py | 457 + src/_utils/_typing.py | 156 + src/_utils/_utils.py | 433 + src/_version.py | 4 + src/py.typed | 0 src/resources/__init__.py | 131 + src/resources/authentication.py | 172 + src/resources/login_portals.py | 362 + src/resources/namespaces.py | 112 + src/resources/registry.py | 923 ++ src/resources/rules.py | 552 + src/resources/scalar_docs.py | 249 + src/resources/schemas/__init__.py | 19 + src/resources/schemas/access_group.py | 209 + src/resources/schemas/schemas.py | 417 + src/resources/schemas/version.py | 277 + src/resources/teams.py | 112 + src/resources/themes.py | 436 + src/types/_400.py | 13 + src/types/_401.py | 13 + src/types/_403.py | 13 + src/types/_404.py | 13 + src/types/_422.py | 13 + src/types/_500.py | 13 + src/types/__init__.py | 96 + src/types/access_group.py | 12 + src/types/active_deployment.py | 16 + src/types/api_document.py | 33 + ...tication_exchange_personal_token_params.py | 14 + ...cation_exchange_personal_token_response.py | 9 + ...thentication_list_current_user_response.py | 10 + src/types/email.py | 9 + src/types/github_project.py | 49 + src/types/github_project_repository.py | 27 + src/types/login_portal.py | 17 + src/types/login_portal_create_params.py | 18 + src/types/login_portal_create_response.py | 10 + src/types/login_portal_delete_response.py | 9 + src/types/login_portal_email.py | 31 + src/types/login_portal_list_response.py | 11 + src/types/login_portal_page.py | 37 + src/types/login_portal_retrieve_response.py | 9 + src/types/login_portal_update_params.py | 12 + src/types/login_portal_update_response.py | 9 + src/types/managed_doc_version.py | 33 + src/types/managed_schema_version.py | 20 + src/types/method.py | 9 + src/types/namespace.py | 9 + src/types/namespace_list_response.py | 10 + src/types/nanoid.py | 9 + ...create_api_document_access_group_params.py | 14 + ...eate_api_document_access_group_response.py | 9 + .../registry_create_api_document_params.py | 26 + .../registry_create_api_document_response.py | 9 + ...stry_create_api_document_version_params.py | 20 + ...ry_create_api_document_version_response.py | 10 + ...delete_api_document_access_group_params.py | 14 + ...lete_api_document_access_group_response.py | 9 + .../registry_delete_api_document_response.py | 9 + ...ry_delete_api_document_version_response.py | 9 + ...egistry_list_all_api_documents_response.py | 11 + ..._api_document_version_metadata_response.py | 10 + .../registry_list_api_documents_response.py | 11 + ..._retrieve_api_document_version_response.py | 9 + .../registry_update_api_document_params.py | 20 + .../registry_update_api_document_response.py | 9 + ...stry_update_api_document_version_params.py | 16 + ...ry_update_api_document_version_response.py | 9 + src/types/rule.py | 24 + ...rule_create_ruleset_access_group_params.py | 14 + ...le_create_ruleset_access_group_response.py | 9 + src/types/rule_create_ruleset_params.py | 22 + src/types/rule_create_ruleset_response.py | 10 + ...rule_delete_ruleset_access_group_params.py | 14 + ...le_delete_ruleset_access_group_response.py | 9 + src/types/rule_delete_ruleset_response.py | 9 + src/types/rule_list_rulesets_response.py | 11 + ...rule_retrieve_ruleset_document_response.py | 9 + src/types/rule_update_ruleset_params.py | 22 + src/types/rule_update_ruleset_response.py | 9 + src/types/scalar_doc_create_guide_params.py | 22 + src/types/scalar_doc_create_guide_response.py | 9 + src/types/scalar_doc_list_guides_response.py | 11 + .../scalar_doc_publish_guide_response.py | 9 + src/types/schema.py | 28 + src/types/schema_create_params.py | 24 + src/types/schema_create_response.py | 10 + src/types/schema_delete_response.py | 9 + src/types/schema_list_response.py | 11 + src/types/schema_update_params.py | 18 + src/types/schema_update_response.py | 9 + src/types/schemas/__init__.py | 12 + .../access_group_create_schema_params.py | 14 + .../access_group_create_schema_response.py | 9 + .../access_group_delete_schema_params.py | 14 + .../access_group_delete_schema_response.py | 9 + .../schemas/version_create_schema_params.py | 14 + .../schemas/version_create_schema_response.py | 10 + .../schemas/version_delete_schema_response.py | 9 + .../version_retrieve_schema_response.py | 9 + src/types/slug.py | 9 + src/types/team.py | 24 + src/types/team_image.py | 9 + src/types/team_list_response.py | 11 + src/types/team_name.py | 9 + src/types/team_summary.py | 19 + src/types/theme.py | 19 + src/types/theme_create_params.py | 18 + src/types/theme_create_response.py | 10 + src/types/theme_delete_response.py | 9 + src/types/theme_list_response.py | 11 + src/types/theme_replace_document_params.py | 12 + src/types/theme_replace_document_response.py | 9 + src/types/theme_retrieve_response.py | 9 + src/types/theme_update_params.py | 14 + src/types/theme_update_response.py | 9 + src/types/timestamp.py | 9 + src/types/uid.py | 12 + src/types/user.py | 30 + src/types/version.py | 9 + tests/smoke-test.py | 732 ++ 157 files changed, 32929 insertions(+), 1 deletion(-) create mode 100644 .gitignore create mode 100644 CHANGELOG.md create mode 100644 LICENSE create mode 100644 SECURITY.md create mode 100644 api.md create mode 100644 openapi.augmented.json create mode 100644 pyproject.toml create mode 100644 release-please-config.json create mode 100644 scalar-sdk.manifest.json create mode 100644 src/__init__.py create mode 100644 src/_base_client.py create mode 100644 src/_client.py create mode 100644 src/_compat.py create mode 100644 src/_constants.py create mode 100644 src/_event_handler.py create mode 100644 src/_exceptions.py create mode 100644 src/_files.py create mode 100644 src/_models.py create mode 100644 src/_qs.py create mode 100644 src/_resource.py create mode 100644 src/_response.py create mode 100644 src/_send_queue.py create mode 100644 src/_streaming.py create mode 100644 src/_types.py create mode 100644 src/_utils/__init__.py create mode 100644 src/_utils/_compat.py create mode 100644 src/_utils/_datetime_parse.py create mode 100644 src/_utils/_json.py create mode 100644 src/_utils/_logs.py create mode 100644 src/_utils/_path.py create mode 100644 src/_utils/_proxy.py create mode 100644 src/_utils/_reflection.py create mode 100644 src/_utils/_resources_proxy.py create mode 100644 src/_utils/_streams.py create mode 100644 src/_utils/_sync.py create mode 100644 src/_utils/_transform.py create mode 100644 src/_utils/_typing.py create mode 100644 src/_utils/_utils.py create mode 100644 src/_version.py create mode 100644 src/py.typed create mode 100644 src/resources/__init__.py create mode 100644 src/resources/authentication.py create mode 100644 src/resources/login_portals.py create mode 100644 src/resources/namespaces.py create mode 100644 src/resources/registry.py create mode 100644 src/resources/rules.py create mode 100644 src/resources/scalar_docs.py create mode 100644 src/resources/schemas/__init__.py create mode 100644 src/resources/schemas/access_group.py create mode 100644 src/resources/schemas/schemas.py create mode 100644 src/resources/schemas/version.py create mode 100644 src/resources/teams.py create mode 100644 src/resources/themes.py create mode 100644 src/types/_400.py create mode 100644 src/types/_401.py create mode 100644 src/types/_403.py create mode 100644 src/types/_404.py create mode 100644 src/types/_422.py create mode 100644 src/types/_500.py create mode 100644 src/types/__init__.py create mode 100644 src/types/access_group.py create mode 100644 src/types/active_deployment.py create mode 100644 src/types/api_document.py create mode 100644 src/types/authentication_exchange_personal_token_params.py create mode 100644 src/types/authentication_exchange_personal_token_response.py create mode 100644 src/types/authentication_list_current_user_response.py create mode 100644 src/types/email.py create mode 100644 src/types/github_project.py create mode 100644 src/types/github_project_repository.py create mode 100644 src/types/login_portal.py create mode 100644 src/types/login_portal_create_params.py create mode 100644 src/types/login_portal_create_response.py create mode 100644 src/types/login_portal_delete_response.py create mode 100644 src/types/login_portal_email.py create mode 100644 src/types/login_portal_list_response.py create mode 100644 src/types/login_portal_page.py create mode 100644 src/types/login_portal_retrieve_response.py create mode 100644 src/types/login_portal_update_params.py create mode 100644 src/types/login_portal_update_response.py create mode 100644 src/types/managed_doc_version.py create mode 100644 src/types/managed_schema_version.py create mode 100644 src/types/method.py create mode 100644 src/types/namespace.py create mode 100644 src/types/namespace_list_response.py create mode 100644 src/types/nanoid.py create mode 100644 src/types/registry_create_api_document_access_group_params.py create mode 100644 src/types/registry_create_api_document_access_group_response.py create mode 100644 src/types/registry_create_api_document_params.py create mode 100644 src/types/registry_create_api_document_response.py create mode 100644 src/types/registry_create_api_document_version_params.py create mode 100644 src/types/registry_create_api_document_version_response.py create mode 100644 src/types/registry_delete_api_document_access_group_params.py create mode 100644 src/types/registry_delete_api_document_access_group_response.py create mode 100644 src/types/registry_delete_api_document_response.py create mode 100644 src/types/registry_delete_api_document_version_response.py create mode 100644 src/types/registry_list_all_api_documents_response.py create mode 100644 src/types/registry_list_api_document_version_metadata_response.py create mode 100644 src/types/registry_list_api_documents_response.py create mode 100644 src/types/registry_retrieve_api_document_version_response.py create mode 100644 src/types/registry_update_api_document_params.py create mode 100644 src/types/registry_update_api_document_response.py create mode 100644 src/types/registry_update_api_document_version_params.py create mode 100644 src/types/registry_update_api_document_version_response.py create mode 100644 src/types/rule.py create mode 100644 src/types/rule_create_ruleset_access_group_params.py create mode 100644 src/types/rule_create_ruleset_access_group_response.py create mode 100644 src/types/rule_create_ruleset_params.py create mode 100644 src/types/rule_create_ruleset_response.py create mode 100644 src/types/rule_delete_ruleset_access_group_params.py create mode 100644 src/types/rule_delete_ruleset_access_group_response.py create mode 100644 src/types/rule_delete_ruleset_response.py create mode 100644 src/types/rule_list_rulesets_response.py create mode 100644 src/types/rule_retrieve_ruleset_document_response.py create mode 100644 src/types/rule_update_ruleset_params.py create mode 100644 src/types/rule_update_ruleset_response.py create mode 100644 src/types/scalar_doc_create_guide_params.py create mode 100644 src/types/scalar_doc_create_guide_response.py create mode 100644 src/types/scalar_doc_list_guides_response.py create mode 100644 src/types/scalar_doc_publish_guide_response.py create mode 100644 src/types/schema.py create mode 100644 src/types/schema_create_params.py create mode 100644 src/types/schema_create_response.py create mode 100644 src/types/schema_delete_response.py create mode 100644 src/types/schema_list_response.py create mode 100644 src/types/schema_update_params.py create mode 100644 src/types/schema_update_response.py create mode 100644 src/types/schemas/__init__.py create mode 100644 src/types/schemas/access_group_create_schema_params.py create mode 100644 src/types/schemas/access_group_create_schema_response.py create mode 100644 src/types/schemas/access_group_delete_schema_params.py create mode 100644 src/types/schemas/access_group_delete_schema_response.py create mode 100644 src/types/schemas/version_create_schema_params.py create mode 100644 src/types/schemas/version_create_schema_response.py create mode 100644 src/types/schemas/version_delete_schema_response.py create mode 100644 src/types/schemas/version_retrieve_schema_response.py create mode 100644 src/types/slug.py create mode 100644 src/types/team.py create mode 100644 src/types/team_image.py create mode 100644 src/types/team_list_response.py create mode 100644 src/types/team_name.py create mode 100644 src/types/team_summary.py create mode 100644 src/types/theme.py create mode 100644 src/types/theme_create_params.py create mode 100644 src/types/theme_create_response.py create mode 100644 src/types/theme_delete_response.py create mode 100644 src/types/theme_list_response.py create mode 100644 src/types/theme_replace_document_params.py create mode 100644 src/types/theme_replace_document_response.py create mode 100644 src/types/theme_retrieve_response.py create mode 100644 src/types/theme_update_params.py create mode 100644 src/types/theme_update_response.py create mode 100644 src/types/timestamp.py create mode 100644 src/types/uid.py create mode 100644 src/types/user.py create mode 100644 src/types/version.py create mode 100644 tests/smoke-test.py diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..0054954 --- /dev/null +++ b/.gitignore @@ -0,0 +1,10 @@ +# Generated by Scalar SDK Generator. +__pycache__/ +*.py[cod] +*.egg-info/ +.venv/ +dist/ +build/ +.mypy_cache/ +.pytest_cache/ +.ruff_cache/ diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..b2f6c56 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,5 @@ +# Changelog + +## 0.1.9 + +- Initial generated SDK release. diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..a121855 --- /dev/null +++ b/LICENSE @@ -0,0 +1,3 @@ +SPDX-License-Identifier: MIT + +See the project repository for the full license text. diff --git a/README.md b/README.md index d6af3b4..977fae0 100644 --- a/README.md +++ b/README.md @@ -1 +1,226 @@ -# scalar-python \ No newline at end of file +# Scalar API + +Generated Python SDK for Scalar API. +API for managing Scalar platform resources. + +## TypeScript SDK + +For TypeScript, we provide a SDK that makes using our API even easier. + +### Install + +```bash +npm add @scalar/sdk +``` + +### Get a Scalar API key + +Create an API key in your Scalar account: + +- Dashboard: https://dashboard.scalar.com/account +- Store it in `.env`, for example: + +```bash +SCALAR_API_KEY=your_personal_token +``` + +### Exchange your API key for an access token + +The personal token is not an access token. Exchange it first with `postv1AuthExchange`. + +If you use the personal token directly for authenticated API calls, the API returns `401 Invalid authentication token`. + +```ts +import { Scalar } from '@scalar/sdk' + +const scalar = new Scalar() + +const exchange = await scalar.auth.postv1AuthExchange({ + personalToken: process.env.SCALAR_API_KEY!, +}) + +const accessToken = exchange.accessToken +``` + +### Use the access token + +Construct a second client with bearer auth. Use this authenticated client for API calls. + +```ts +import { Scalar } from '@scalar/sdk' + +const scalar = new Scalar() + +const exchange = await scalar.auth.postv1AuthExchange({ + personalToken: process.env.SCALAR_API_KEY!, +}) + +const authedScalar = new Scalar({ + bearerAuth: exchange.accessToken, +}) +``` + +### Notes + +- The exchange request itself can be made from a client constructed with no arguments (`new Scalar()`). +- The exchanged access token is valid for 12 hours. +- Timestamps are Unix seconds. + +### Read more + +- [@scalar/sdk on npm](https://www.npmjs.com/package/@scalar/sdk) + +
+ +## Contents + +- [Installation](#installation) +- [Usage](#usage) +- [API Reference](./api.md) +- [Async](#async) +- [Authentication](#authentication) +- [Errors](#errors) +- [Client Options](#client-options) +- [Retries and Timeouts](#retries-and-timeouts) +- [Helpers](#helpers) +- [Logging](#logging) +- [Requirements](#requirements) + +
+ +## Installation + +```sh +pip install scalarApi +``` + +
+ +## Usage + +```python +import os + +from scalar_api import ScalarApi + +client = ScalarApi( + bearer_auth=os.environ.get("BEARER_AUTH"), +) + +registry = client.registry.list_all_api_documents() +print(registry) +``` + +The examples in the following sections assume a `client` configured as shown above. + +See the [API reference](./api.md) for every available operation. + +
+ +## Async + +Every client has an `Async` counterpart (`AsyncScalarApi`) exposing the same resource tree with `await`. + +```python +import asyncio + +from scalar_api import AsyncScalarApi + +async def main() -> None: + client = AsyncScalarApi() + registry = await client.registry.list_all_api_documents() + +asyncio.run(main()) +``` + +
+ +## Authentication + +Pass credentials to the generated client constructor. Environment variables are read automatically when supported by the target runtime. + +| Option | Type | Default | Description | +| --- | --- | --- | --- | +| `bearer_auth` | `string \| provider` | - | Credential for the BearerAuth scheme. Defaults to BEARER_AUTH. | + +Declared schemes: + +- `BearerAuth` bearer token + +
+ +## Errors + +Non-success responses throw generated API errors. Error objects expose status, headers, response body, and request metadata where the target runtime supports it. + +```python +from scalar_api import APIStatusError + +try: + registry = client.registry.list_all_api_documents() +except APIStatusError as err: + print(err.status_code, err.message) + raise +``` + +Documented error statuses: `400`, `401`, `403`, `404`, `422`, `500`. + +
+ +## Client Options + +Configure the generated client by setting any of these options when you create it. + +```python +from scalar_api import ScalarApi + +client = ScalarApi( + timeout=60.0, + max_retries=2, +) +``` + +| Option | Type | Default | Description | +| --- | --- | --- | --- | +| `bearer_auth` | `str \| None` | `os.environ.get("BEARER_AUTH")` | Credential for the BearerAuth scheme. | +| `base_url` | `str \| httpx.URL \| None` | - | Override the default API base URL. | +| `timeout` | `float \| Timeout \| None` | `60.0` | Maximum time in seconds to wait for a response before aborting a request. | +| `max_retries` | `int` | `2` | Number of retries for temporary failures. | +| `default_headers` | `Mapping[str, str] \| None` | - | Headers sent with every request. | +| `default_query` | `Mapping[str, object] \| None` | - | Query parameters sent with every request. | + +
+ +## Retries and Timeouts + +Generated clients support request timeouts and retry temporary failures such as network errors, 408, 409, 429, and 5xx responses. Retry delays honor `Retry-After` headers when present. Tune the retry and timeout client options shown above, or override them per request. + +
+ +## Helpers + +- Use `client.with_raw_response..(...)` to access the raw `httpx.Response` and parse it yourself. +- Use `client.with_streaming_response..(...)` to stream a response body without buffering it. + +
+ +## Logging + +- Set the `SCALAR_LOG` environment variable to `info` or `debug` to enable HTTP logging. +- Logs are emitted through the standard `logging` module under the `scalar_api` logger. + +
+ +## Requirements + +- Python 3.8 or newer + +Powered by Scalar. + + +## Contributions + +This SDK is generated programmatically. Manual edits to generated files will be +overwritten on the next build. + +### SDK created by [Scalar](https://www.scalar.com/?utm_source=scalar-typescript-sdk-python&utm_campaign=sdk) diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 0000000..22d4cea --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,3 @@ +# Security Policy + +Please report any vulnerabilities through the standard issue tracker. diff --git a/api.md b/api.md new file mode 100644 index 0000000..397a3cc --- /dev/null +++ b/api.md @@ -0,0 +1,837 @@ +# Scalar Python API + +Complete reference of every operation, grouped by resource. See [the README](./README.md) for usage and configuration. + +## Contents + +- [`Registry`](#registry) + - [List all API Documents](#list-all-api-documents) + - [List API Documents in a namespace](#list-api-documents-in-a-namespace) + - [Create API Document](#create-api-document) + - [Update API Document metadata](#update-api-document-metadata) + - [Delete API Document](#delete-api-document) + - [Get API Document](#get-api-document) + - [Update API Document version](#update-api-document-version) + - [Delete API Document version](#delete-api-document-version) + - [Get API Document version metadata](#get-api-document-version-metadata) + - [Create API Document version](#create-api-document-version) + - [Add access group](#add-access-group) + - [Remove access group](#remove-access-group) +- [`Schemas`](#schemas) + - [List all shared components](#list-all-shared-components) + - [Create a shared component](#create-a-shared-component) + - [Update shared component metadata](#update-shared-component-metadata) + - [Delete a shared component](#delete-a-shared-component) + - [`Schemas Version`](#schemas-version) + - [Get a shared component document](#get-a-shared-component-document) + - [Delete a shared component version](#delete-a-shared-component-version) + - [Create a shared component version](#create-a-shared-component-version) + - [`Schemas AccessGroup`](#schemas-accessgroup) + - [Add shared component access group](#add-shared-component-access-group) + - [Remove shared component access group](#remove-shared-component-access-group) +- [`LoginPortals`](#loginportals) + - [Get a login portal](#get-a-login-portal) + - [Update portal metadata](#update-portal-metadata) + - [Delete a login portal](#delete-a-login-portal) + - [Create a portal](#create-a-portal) + - [List all portals](#list-all-portals) +- [`Rules`](#rules) + - [List all rules](#list-all-rules) + - [Create a rule](#create-a-rule) + - [Update rule metadata](#update-rule-metadata) + - [Delete a rule](#delete-a-rule) + - [Get a rule](#get-a-rule) + - [Add rule access group](#add-rule-access-group) + - [Remove rule access group](#remove-rule-access-group) +- [`Themes`](#themes) + - [List all themes](#list-all-themes) + - [Create a theme](#create-a-theme) + - [Update theme metadata](#update-theme-metadata) + - [Update theme document](#update-theme-document) + - [Delete a theme](#delete-a-theme) + - [Get a theme](#get-a-theme) +- [`Teams`](#teams) + - [List teams](#list-teams) +- [`ScalarDocs`](#scalardocs) + - [List all projects](#list-all-projects) + - [Create a project](#create-a-project) + - [Publish a project](#publish-a-project) +- [`Namespaces`](#namespaces) + - [List namespaces](#list-namespaces) +- [`Authentication`](#authentication) + - [Exchange token](#exchange-token) + - [Get current user](#get-current-user) + +## Setup + +```python +import os + +from scalar_api import ScalarApi + +client = ScalarApi( + bearer_auth=os.environ.get("BEARER_AUTH"), +) +``` + +## `Registry` + +### List all API Documents + +List all API documents across every namespace the caller can access. + +| Direction | Type | +| --- | --- | +| Response | [`RegistryListAllApiDocumentsResponse`](./src/types/registry_list_all_api_documents_response.py) | + +```python +registry = client.registry.list_all_api_documents() +``` + +### List API Documents in a namespace + +List API documents in a namespace. + +| Direction | Type | +| --- | --- | +| Response | [`RegistryListApiDocumentsResponse`](./src/types/registry_list_api_documents_response.py) | + +```python +registry = client.registry.list_api_documents( + namespace="namespace", +) +``` + +### Create API Document + +Create an API document. + +| Direction | Type | +| --- | --- | +| Request | [`RegistryCreateApiDocumentParams`](./src/types/registry_create_api_document_params.py) | +| Response | [`RegistryCreateApiDocumentResponse`](./src/types/registry_create_api_document_response.py) | + +```python +registry = client.registry.create_api_document( + namespace="namespace", + title="", + version="", + slug="", + document="", + idempotency_key="", +) +``` + +### Update API Document metadata + +Update metadata for an API document. + +| Direction | Type | +| --- | --- | +| Request | [`RegistryUpdateApiDocumentParams`](./src/types/registry_update_api_document_params.py) | +| Response | [`RegistryUpdateApiDocumentResponse`](./src/types/registry_update_api_document_response.py) | + +```python +registry = client.registry.update_api_document( + namespace="namespace", + slug="slug", + idempotency_key="", +) +``` + +### Delete API Document + +Delete an API document and all versions. + +| Direction | Type | +| --- | --- | +| Response | [`RegistryDeleteApiDocumentResponse`](./src/types/registry_delete_api_document_response.py) | + +```python +registry = client.registry.delete_api_document( + namespace="namespace", + slug="slug", + idempotency_key="", +) +``` + +### Get API Document + +Get a specific API document version. + +| Direction | Type | +| --- | --- | +| Response | [`RegistryRetrieveApiDocumentVersionResponse`](./src/types/registry_retrieve_api_document_version_response.py) | + +```python +registry = client.registry.retrieve_api_document_version( + namespace="namespace", + slug="slug", + semver="semver", +) +``` + +### Update API Document version + +Update the registry file content for an API document version. + +| Direction | Type | +| --- | --- | +| Request | [`RegistryUpdateApiDocumentVersionParams`](./src/types/registry_update_api_document_version_params.py) | +| Response | [`RegistryUpdateApiDocumentVersionResponse`](./src/types/registry_update_api_document_version_response.py) | + +```python +registry = client.registry.update_api_document_version( + namespace="namespace", + slug="slug", + semver="semver", + document="", + idempotency_key="", +) +``` + +### Delete API Document version + +Delete a specific API document version. + +| Direction | Type | +| --- | --- | +| Response | [`RegistryDeleteApiDocumentVersionResponse`](./src/types/registry_delete_api_document_version_response.py) | + +```python +registry = client.registry.delete_api_document_version( + namespace="namespace", + slug="slug", + semver="semver", + idempotency_key="", +) +``` + +### Get API Document version metadata + +Get metadata (uid, content shas, version sha, tags) for a specific API document version. + +| Direction | Type | +| --- | --- | +| Response | [`RegistryListApiDocumentVersionMetadataResponse`](./src/types/registry_list_api_document_version_metadata_response.py) | + +```python +registry = client.registry.list_api_document_version_metadata( + namespace="namespace", + slug="slug", + semver="semver", +) +``` + +### Create API Document version + +Create a new API document version. + +| Direction | Type | +| --- | --- | +| Request | [`RegistryCreateApiDocumentVersionParams`](./src/types/registry_create_api_document_version_params.py) | +| Response | [`RegistryCreateApiDocumentVersionResponse`](./src/types/registry_create_api_document_version_response.py) | + +```python +registry = client.registry.create_api_document_version( + namespace="namespace", + slug="slug", + version="", + document="", + idempotency_key="", +) +``` + +### Add access group + +Add an access group to an API document. + +| Direction | Type | +| --- | --- | +| Request | [`RegistryCreateApiDocumentAccessGroupParams`](./src/types/registry_create_api_document_access_group_params.py) | +| Response | [`RegistryCreateApiDocumentAccessGroupResponse`](./src/types/registry_create_api_document_access_group_response.py) | + +```python +registry = client.registry.create_api_document_access_group( + namespace="namespace", + slug="slug", + access_group_slug="", + idempotency_key="", +) +``` + +### Remove access group + +Remove an access group from an API document. + +| Direction | Type | +| --- | --- | +| Request | [`RegistryDeleteApiDocumentAccessGroupParams`](./src/types/registry_delete_api_document_access_group_params.py) | +| Response | [`RegistryDeleteApiDocumentAccessGroupResponse`](./src/types/registry_delete_api_document_access_group_response.py) | + +```python +registry = client.registry.delete_api_document_access_group( + namespace="namespace", + slug="slug", + access_group_slug="", + idempotency_key="", +) +``` + +## `Schemas` + +### List all shared components + +List schemas in a namespace. + +| Direction | Type | +| --- | --- | +| Response | [`SchemaListResponse`](./src/types/schema_list_response.py) | + +```python +schema = client.schemas.list( + namespace="namespace", +) +``` + +### Create a shared component + +Create a schema in a namespace. + +| Direction | Type | +| --- | --- | +| Request | [`SchemaCreateParams`](./src/types/schema_create_params.py) | +| Response | [`SchemaCreateResponse`](./src/types/schema_create_response.py) | + +```python +schema = client.schemas.create( + namespace="namespace", + title="", + version="", + slug="", + document="", + idempotency_key="", +) +``` + +### Update shared component metadata + +Update schema metadata. + +| Direction | Type | +| --- | --- | +| Request | [`SchemaUpdateParams`](./src/types/schema_update_params.py) | +| Response | [`SchemaUpdateResponse`](./src/types/schema_update_response.py) | + +```python +schema = client.schemas.update( + namespace="namespace", + slug="slug", + idempotency_key="", +) +``` + +### Delete a shared component + +Delete a schema and all related versions. + +| Direction | Type | +| --- | --- | +| Response | [`SchemaDeleteResponse`](./src/types/schema_delete_response.py) | + +```python +schema = client.schemas.delete( + namespace="namespace", + slug="slug", + idempotency_key="", +) +``` + +### `Schemas Version` + +#### Get a shared component document + +Get a specific schema version document. + +| Direction | Type | +| --- | --- | +| Response | [`VersionRetrieveSchemaResponse`](./src/types/schemas/version_retrieve_schema_response.py) | + +```python +version = client.schemas.version.retrieve_schema( + namespace="namespace", + slug="slug", + semver="semver", +) +``` + +#### Delete a shared component version + +Delete a schema version. + +| Direction | Type | +| --- | --- | +| Response | [`VersionDeleteSchemaResponse`](./src/types/schemas/version_delete_schema_response.py) | + +```python +version = client.schemas.version.delete_schema( + namespace="namespace", + slug="slug", + semver="semver", + idempotency_key="", +) +``` + +#### Create a shared component version + +Create a schema version. + +| Direction | Type | +| --- | --- | +| Request | [`VersionCreateSchemaParams`](./src/types/schemas/version_create_schema_params.py) | +| Response | [`VersionCreateSchemaResponse`](./src/types/schemas/version_create_schema_response.py) | + +```python +version = client.schemas.version.create_schema( + namespace="namespace", + slug="slug", + version="", + document="", + idempotency_key="", +) +``` + +### `Schemas AccessGroup` + +#### Add shared component access group + +Add an access group to a schema. + +| Direction | Type | +| --- | --- | +| Request | [`AccessGroupCreateSchemaParams`](./src/types/schemas/access_group_create_schema_params.py) | +| Response | [`AccessGroupCreateSchemaResponse`](./src/types/schemas/access_group_create_schema_response.py) | + +```python +access_group = client.schemas.access_group.create_schema( + namespace="namespace", + slug="slug", + access_group_slug="", + idempotency_key="", +) +``` + +#### Remove shared component access group + +Remove an access group from a schema. + +| Direction | Type | +| --- | --- | +| Request | [`AccessGroupDeleteSchemaParams`](./src/types/schemas/access_group_delete_schema_params.py) | +| Response | [`AccessGroupDeleteSchemaResponse`](./src/types/schemas/access_group_delete_schema_response.py) | + +```python +access_group = client.schemas.access_group.delete_schema( + namespace="namespace", + slug="slug", + access_group_slug="", + idempotency_key="", +) +``` + +## `LoginPortals` + +### Get a login portal + +Get a login portal by slug. + +| Direction | Type | +| --- | --- | +| Response | [`LoginPortalRetrieveResponse`](./src/types/login_portal_retrieve_response.py) | + +```python +login_portal = client.login_portals.retrieve( + slug="slug", +) +``` + +### Update portal metadata + +Update metadata for a login portal. + +| Direction | Type | +| --- | --- | +| Request | [`LoginPortalUpdateParams`](./src/types/login_portal_update_params.py) | +| Response | [`LoginPortalUpdateResponse`](./src/types/login_portal_update_response.py) | + +```python +login_portal = client.login_portals.update( + slug="slug", + idempotency_key="", +) +``` + +### Delete a login portal + +Delete a login portal. + +| Direction | Type | +| --- | --- | +| Response | [`LoginPortalDeleteResponse`](./src/types/login_portal_delete_response.py) | + +```python +login_portal = client.login_portals.delete( + slug="slug", + idempotency_key="", +) +``` + +### Create a portal + +Create a login portal for the current team. + +| Direction | Type | +| --- | --- | +| Request | [`LoginPortalCreateParams`](./src/types/login_portal_create_params.py) | +| Response | [`LoginPortalCreateResponse`](./src/types/login_portal_create_response.py) | + +```python +login_portal = client.login_portals.create( + title="", + slug="", + email={"logo": "", "logo_size": "100", "button_text": "Login", "message": "Click to access private documentation hosted by scalar.com", "title": "Private Docs", "main_color": "#2a2f45", "main_background": "#f6f6f6", "card_color": "2a2f45", "card_background": "#fff", "button_color": "#fff", "button_background": "#0f0f0f"}, + page={"title": "Scalar Private Docs", "description": "Login to access your documentation", "head": "", "script": "", "theme": "", "company_name": "", "logo": "", "logo_url": "", "favicon": "", "terms_link": "", "privacy_link": "", "form_title": "Scalar Private Docs", "form_description": "Login to access your documentation", "form_image": ""}, + idempotency_key="", +) +``` + +### List all portals + +List all login portals for the current team. + +| Direction | Type | +| --- | --- | +| Response | [`LoginPortalListResponse`](./src/types/login_portal_list_response.py) | + +```python +login_portal = client.login_portals.list() +``` + +## `Rules` + +### List all rules + +List all rulesets in a namespace. + +| Direction | Type | +| --- | --- | +| Response | [`RuleListRulesetsResponse`](./src/types/rule_list_rulesets_response.py) | + +```python +rule = client.rules.list_rulesets( + namespace="namespace", +) +``` + +### Create a rule + +Create a rule in a namespace. + +| Direction | Type | +| --- | --- | +| Request | [`RuleCreateRulesetParams`](./src/types/rule_create_ruleset_params.py) | +| Response | [`RuleCreateRulesetResponse`](./src/types/rule_create_ruleset_response.py) | + +```python +rule = client.rules.create_ruleset( + namespace="namespace", + title="", + slug="", + document="", + idempotency_key="", +) +``` + +### Update rule metadata + +Update rule metadata by slug. + +| Direction | Type | +| --- | --- | +| Request | [`RuleUpdateRulesetParams`](./src/types/rule_update_ruleset_params.py) | +| Response | [`RuleUpdateRulesetResponse`](./src/types/rule_update_ruleset_response.py) | + +```python +rule = client.rules.update_ruleset( + namespace="namespace", + slug="slug", + idempotency_key="", +) +``` + +### Delete a rule + +Delete a rule by slug. + +| Direction | Type | +| --- | --- | +| Response | [`RuleDeleteRulesetResponse`](./src/types/rule_delete_ruleset_response.py) | + +```python +rule = client.rules.delete_ruleset( + namespace="namespace", + slug="slug", + idempotency_key="", +) +``` + +### Get a rule + +Get a rule document by slug. + +| Direction | Type | +| --- | --- | +| Response | [`RuleRetrieveRulesetDocumentResponse`](./src/types/rule_retrieve_ruleset_document_response.py) | + +```python +rule = client.rules.retrieve_ruleset_document( + namespace="namespace", + slug="slug", +) +``` + +### Add rule access group + +Grant an access group to a rule. + +| Direction | Type | +| --- | --- | +| Request | [`RuleCreateRulesetAccessGroupParams`](./src/types/rule_create_ruleset_access_group_params.py) | +| Response | [`RuleCreateRulesetAccessGroupResponse`](./src/types/rule_create_ruleset_access_group_response.py) | + +```python +rule = client.rules.create_ruleset_access_group( + namespace="namespace", + slug="slug", + access_group_slug="", + idempotency_key="", +) +``` + +### Remove rule access group + +Remove an access group from a rule. + +| Direction | Type | +| --- | --- | +| Request | [`RuleDeleteRulesetAccessGroupParams`](./src/types/rule_delete_ruleset_access_group_params.py) | +| Response | [`RuleDeleteRulesetAccessGroupResponse`](./src/types/rule_delete_ruleset_access_group_response.py) | + +```python +rule = client.rules.delete_ruleset_access_group( + namespace="namespace", + slug="slug", + access_group_slug="", + idempotency_key="", +) +``` + +## `Themes` + +### List all themes + +List all team themes. + +| Direction | Type | +| --- | --- | +| Response | [`ThemeListResponse`](./src/types/theme_list_response.py) | + +```python +theme = client.themes.list() +``` + +### Create a theme + +Create a team theme. + +| Direction | Type | +| --- | --- | +| Request | [`ThemeCreateParams`](./src/types/theme_create_params.py) | +| Response | [`ThemeCreateResponse`](./src/types/theme_create_response.py) | + +```python +theme = client.themes.create( + name="", + slug="", + document="", + idempotency_key="", +) +``` + +### Update theme metadata + +Update theme metadata. + +| Direction | Type | +| --- | --- | +| Request | [`ThemeUpdateParams`](./src/types/theme_update_params.py) | +| Response | [`ThemeUpdateResponse`](./src/types/theme_update_response.py) | + +```python +theme = client.themes.update( + slug="slug", + idempotency_key="", +) +``` + +### Update theme document + +Replace the theme document. + +| Direction | Type | +| --- | --- | +| Request | [`ThemeReplaceDocumentParams`](./src/types/theme_replace_document_params.py) | +| Response | [`ThemeReplaceDocumentResponse`](./src/types/theme_replace_document_response.py) | + +```python +theme = client.themes.replace_document( + slug="slug", + document="", + idempotency_key="", +) +``` + +### Delete a theme + +Delete a theme by slug. + +| Direction | Type | +| --- | --- | +| Response | [`ThemeDeleteResponse`](./src/types/theme_delete_response.py) | + +```python +theme = client.themes.delete( + slug="slug", + idempotency_key="", +) +``` + +### Get a theme + +Get the theme document by slug. + +| Direction | Type | +| --- | --- | +| Response | [`ThemeRetrieveResponse`](./src/types/theme_retrieve_response.py) | + +```python +theme = client.themes.retrieve( + slug="slug", +) +``` + +## `Teams` + +### List teams + +List all available teams + +| Direction | Type | +| --- | --- | +| Response | [`TeamListResponse`](./src/types/team_list_response.py) | + +```python +team = client.teams.list() +``` + +## `ScalarDocs` + +### List all projects + +List all guide projects. + +| Direction | Type | +| --- | --- | +| Response | [`ScalarDocListGuidesResponse`](./src/types/scalar_doc_list_guides_response.py) | + +```python +scalar_doc = client.scalar_docs.list_guides() +``` + +### Create a project + +Create a guide project. + +| Direction | Type | +| --- | --- | +| Request | [`ScalarDocCreateGuideParams`](./src/types/scalar_doc_create_guide_params.py) | +| Response | [`ScalarDocCreateGuideResponse`](./src/types/scalar_doc_create_guide_response.py) | + +```python +scalar_doc = client.scalar_docs.create_guide( + name="", + is_private=False, + allowed_users=[], + allowed_domains=[], + idempotency_key="", +) +``` + +### Publish a project + +Start a new publish process. + +| Direction | Type | +| --- | --- | +| Response | [`ScalarDocPublishGuideResponse`](./src/types/scalar_doc_publish_guide_response.py) | + +```python +scalar_doc = client.scalar_docs.publish_guide( + slug="slug", + idempotency_key="", +) +``` + +## `Namespaces` + +### List namespaces + +Get all namespaces for the current team + +| Direction | Type | +| --- | --- | +| Response | [`NamespaceListResponse`](./src/types/namespace_list_response.py) | + +```python +namespace = client.namespaces.list() +``` + +## `Authentication` + +### Exchange token + +Exchange an API key for an access token. + +| Direction | Type | +| --- | --- | +| Request | [`AuthenticationExchangePersonalTokenParams`](./src/types/authentication_exchange_personal_token_params.py) | +| Response | [`AuthenticationExchangePersonalTokenResponse`](./src/types/authentication_exchange_personal_token_response.py) | + +```python +authentication = client.authentication.exchange_personal_token( + personal_token="", + idempotency_key="", +) +``` + +### Get current user + +Get the authenticated user, including their available teams and theme. + +| Direction | Type | +| --- | --- | +| Response | [`AuthenticationListCurrentUserResponse`](./src/types/authentication_list_current_user_response.py) | + +```python +authentication = client.authentication.list_current_user() +``` diff --git a/openapi.augmented.json b/openapi.augmented.json new file mode 100644 index 0000000..2a73adf --- /dev/null +++ b/openapi.augmented.json @@ -0,0 +1,7841 @@ +{ + "openapi": "3.1.1", + "info": { + "title": "Scalar API", + "description": "API for managing Scalar platform resources.\n\n## TypeScript SDK\n\nFor TypeScript, we provide a SDK that makes using our API even easier.\n\n### Install\n\n```bash\nnpm add @scalar/sdk\n```\n\n### Get a Scalar API key\n\nCreate an API key in your Scalar account:\n\n- Dashboard: https://dashboard.scalar.com/account\n- Store it in `.env`, for example:\n\n```bash\nSCALAR_API_KEY=your_personal_token\n```\n\n### Exchange your API key for an access token\n\nThe personal token is not an access token. Exchange it first with `postv1AuthExchange`.\n\nIf you use the personal token directly for authenticated API calls, the API returns `401 Invalid authentication token`.\n\n```ts\nimport { Scalar } from '@scalar/sdk'\n\nconst scalar = new Scalar()\n\nconst exchange = await scalar.auth.postv1AuthExchange({\n personalToken: process.env.SCALAR_API_KEY!,\n})\n\nconst accessToken = exchange.accessToken\n```\n\n### Use the access token\n\nConstruct a second client with bearer auth. Use this authenticated client for API calls.\n\n```ts\nimport { Scalar } from '@scalar/sdk'\n\nconst scalar = new Scalar()\n\nconst exchange = await scalar.auth.postv1AuthExchange({\n personalToken: process.env.SCALAR_API_KEY!,\n})\n\nconst authedScalar = new Scalar({\n bearerAuth: exchange.accessToken,\n})\n```\n\n### Notes\n\n- The exchange request itself can be made from a client constructed with no arguments (`new Scalar()`).\n- The exchanged access token is valid for 12 hours.\n- Timestamps are Unix seconds.\n\n### Read more\n\n- [@scalar/sdk on npm](https://www.npmjs.com/package/@scalar/sdk)", + "version": "0.1.5", + "contact": { + "name": "Marc from Scalar", + "url": "https://scalar.com", + "email": "support@scalar.com" + }, + "x-scalar-sdk-installation": [ + { + "lang": "TypeScript", + "description": "```sh\nnpm install @scalar/sdk\n```" + }, + { + "lang": "Python", + "description": "```sh\npip install scalarApi\n```" + }, + { + "lang": "Go", + "description": "```sh\ngo get scalar-api\n```" + } + ] + }, + "servers": [ + { + "url": "https://access.scalar.com" + } + ], + "tags": [ + { + "name": "Registry", + "description": "Registry" + }, + { + "name": "Schemas", + "description": "Schemas" + }, + { + "name": "Login Portals", + "description": "Login Portals" + }, + { + "name": "Rules", + "description": "Rules" + }, + { + "name": "Themes", + "description": "Themes" + }, + { + "name": "Teams", + "description": "Teams" + }, + { + "name": "Scalar Docs", + "description": "Scalar Docs" + }, + { + "name": "Namespaces", + "description": "Namespaces" + }, + { + "name": "Authentication", + "description": "Authentication" + } + ], + "components": { + "securitySchemes": { + "BearerAuth": { + "type": "http", + "scheme": "bearer", + "bearerFormat": "JWT" + } + }, + "schemas": { + "400": { + "type": "object", + "properties": { + "message": { + "type": "string" + }, + "code": { + "type": "string" + } + }, + "required": [ + "message", + "code" + ] + }, + "401": { + "type": "object", + "properties": { + "message": { + "type": "string" + }, + "code": { + "type": "string" + } + }, + "required": [ + "message", + "code" + ] + }, + "403": { + "type": "object", + "properties": { + "message": { + "type": "string" + }, + "code": { + "type": "string" + } + }, + "required": [ + "message", + "code" + ] + }, + "404": { + "type": "object", + "properties": { + "message": { + "type": "string" + }, + "code": { + "type": "string" + } + }, + "required": [ + "message", + "code" + ] + }, + "422": { + "type": "object", + "properties": { + "message": { + "type": "string" + }, + "code": { + "type": "string" + } + }, + "required": [ + "message", + "code" + ] + }, + "500": { + "type": "object", + "properties": { + "message": { + "type": "string" + }, + "code": { + "type": "string" + } + }, + "required": [ + "message", + "code" + ] + }, + "api-document": { + "type": "object", + "properties": { + "uid": { + "default": "nanoid()", + "$ref": "#/components/schemas/nanoid" + }, + "version": { + "$ref": "#/components/schemas/version" + }, + "title": { + "default": "", + "type": "string", + "maxLength": 100 + }, + "slug": { + "default": "randomManagedDocSlug()", + "$ref": "#/components/schemas/slug" + }, + "description": { + "default": "", + "type": "string" + }, + "namespace": { + "$ref": "#/components/schemas/namespace" + }, + "isPrivate": { + "default": false, + "type": "boolean" + }, + "tags": { + "default": [] + }, + "versions": { + "type": "array", + "items": { + "$ref": "#/components/schemas/managed-doc-version" + } + } + }, + "required": [ + "uid", + "version", + "title", + "slug", + "description", + "namespace", + "isPrivate", + "tags", + "versions" + ], + "additionalProperties": false + }, + "nanoid": { + "type": "string", + "minLength": 5 + }, + "version": { + "type": "string", + "minLength": 1 + }, + "slug": { + "type": "string", + "minLength": 3, + "maxLength": 60, + "pattern": "^[a-z](?:[a-z0-9-]*[a-z0-9])?$" + }, + "namespace": { + "type": "string", + "minLength": 3, + "maxLength": 50, + "pattern": "^[a-zA-Z0-9-_]+$" + }, + "managed-doc-version": { + "type": "object", + "properties": { + "uid": { + "$ref": "#/components/schemas/nanoid" + }, + "createdAt": { + "type": "number" + }, + "version": { + "$ref": "#/components/schemas/version" + }, + "upgraded": { + "default": false, + "type": "boolean" + }, + "embedStatus": { + "default": null, + "anyOf": [ + { + "type": "string", + "enum": [ + "complete", + "failed" + ] + }, + { + "type": "null" + } + ] + }, + "tags": { + "default": [], + "type": "array", + "items": { + "type": "string" + } + }, + "tools": { + "type": "array", + "items": { + "type": "object", + "properties": { + "path": { + "type": "string" + }, + "method": { + "$ref": "#/components/schemas/method" + }, + "enabledTools": { + "type": "array", + "items": { + "type": "string", + "enum": [ + "execute-request", + "get-mini-openapi-spec" + ] + } + } + }, + "required": [ + "path", + "method", + "enabledTools" + ], + "additionalProperties": false + } + }, + "yamlSha": { + "type": "string" + }, + "jsonSha": { + "type": "string" + }, + "versionSha": { + "type": "string" + } + }, + "required": [ + "uid", + "createdAt", + "version", + "upgraded", + "embedStatus", + "tags" + ], + "additionalProperties": false + }, + "method": { + "type": "string", + "enum": [ + "delete", + "get", + "head", + "options", + "patch", + "post", + "put", + "trace" + ] + }, + "access-group": { + "type": "object", + "properties": { + "accessGroupSlug": { + "$ref": "#/components/schemas/slug" + } + }, + "required": [ + "accessGroupSlug" + ], + "additionalProperties": false + }, + "schema": { + "type": "object", + "properties": { + "uid": { + "default": "nanoid()", + "$ref": "#/components/schemas/nanoid" + }, + "title": { + "default": "", + "type": "string", + "maxLength": 100 + }, + "description": { + "default": "", + "type": "string" + }, + "slug": { + "default": "randomManagedDocSlug()", + "$ref": "#/components/schemas/slug" + }, + "namespace": { + "$ref": "#/components/schemas/namespace" + }, + "isPrivate": { + "default": false, + "type": "boolean" + }, + "versions": { + "type": "array", + "items": { + "$ref": "#/components/schemas/managed-schema-version" + } + } + }, + "required": [ + "uid", + "title", + "description", + "slug", + "namespace", + "isPrivate", + "versions" + ], + "additionalProperties": false + }, + "managed-schema-version": { + "type": "object", + "properties": { + "uid": { + "default": "nanoid()", + "$ref": "#/components/schemas/nanoid" + }, + "createdAt": { + "default": "unixTimestamp()", + "$ref": "#/components/schemas/timestamp" + }, + "updatedAt": { + "default": "unixTimestamp()", + "$ref": "#/components/schemas/timestamp" + }, + "version": { + "default": "0.0.1", + "$ref": "#/components/schemas/version" + } + }, + "required": [ + "uid", + "createdAt", + "updatedAt", + "version" + ], + "additionalProperties": false + }, + "timestamp": { + "type": "integer", + "minimum": 0, + "maximum": 9007199254740991 + }, + "uid": { + "type": "object", + "properties": { + "uid": { + "$ref": "#/components/schemas/nanoid" + } + }, + "required": [ + "uid" + ], + "additionalProperties": false + }, + "login-portal-email": { + "type": "object", + "properties": { + "logo": { + "default": "", + "type": "string" + }, + "logoSize": { + "default": "100", + "type": "string" + }, + "buttonText": { + "default": "Login", + "type": "string", + "maxLength": 50 + }, + "message": { + "default": "Click to access private documentation hosted by scalar.com", + "type": "string", + "maxLength": 1000 + }, + "title": { + "default": "Private Docs", + "type": "string", + "maxLength": 100 + }, + "mainColor": { + "default": "#2a2f45", + "type": "string", + "maxLength": 100 + }, + "mainBackground": { + "default": "#f6f6f6", + "type": "string", + "maxLength": 100 + }, + "cardColor": { + "default": "2a2f45", + "type": "string", + "maxLength": 100 + }, + "cardBackground": { + "default": "#fff", + "type": "string", + "maxLength": 100 + }, + "buttonColor": { + "default": "#fff", + "type": "string", + "maxLength": 100 + }, + "buttonBackground": { + "default": "#0f0f0f", + "type": "string", + "maxLength": 100 + } + }, + "required": [ + "logo", + "logoSize", + "buttonText", + "message", + "title", + "mainColor", + "mainBackground", + "cardColor", + "cardBackground", + "buttonColor", + "buttonBackground" + ], + "additionalProperties": false + }, + "login-portal-page": { + "type": "object", + "properties": { + "title": { + "default": "Scalar Private Docs", + "type": "string", + "maxLength": 100 + }, + "description": { + "default": "Login to access your documentation", + "type": "string", + "maxLength": 500 + }, + "head": { + "default": "", + "type": "string" + }, + "script": { + "default": "", + "type": "string" + }, + "theme": { + "default": "", + "type": "string" + }, + "companyName": { + "default": "", + "type": "string", + "maxLength": 100 + }, + "logo": { + "default": "", + "type": "string" + }, + "logoURL": { + "default": "", + "type": "string" + }, + "favicon": { + "default": "", + "type": "string" + }, + "termsLink": { + "default": "", + "type": "string" + }, + "privacyLink": { + "default": "", + "type": "string" + }, + "formTitle": { + "default": "Scalar Private Docs", + "type": "string", + "maxLength": 100 + }, + "formDescription": { + "default": "Login to access your documentation", + "type": "string", + "maxLength": 500 + }, + "formImage": { + "default": "", + "type": "string" + } + }, + "required": [ + "title", + "description", + "head", + "script", + "theme", + "companyName", + "logo", + "logoURL", + "favicon", + "termsLink", + "privacyLink", + "formTitle", + "formDescription", + "formImage" + ], + "additionalProperties": false + }, + "login-portal": { + "type": "object", + "properties": { + "uid": { + "$ref": "#/components/schemas/nanoid" + }, + "title": { + "type": "string", + "maxLength": 200 + }, + "slug": { + "$ref": "#/components/schemas/slug" + } + }, + "required": [ + "uid", + "title", + "slug" + ], + "additionalProperties": false + }, + "rule": { + "type": "object", + "properties": { + "uid": { + "default": "nanoid()", + "$ref": "#/components/schemas/nanoid" + }, + "title": { + "default": "", + "type": "string", + "maxLength": 100 + }, + "description": { + "default": "", + "type": "string" + }, + "slug": { + "default": "randomManagedDocSlug()", + "$ref": "#/components/schemas/slug" + }, + "namespace": { + "$ref": "#/components/schemas/namespace" + }, + "isPrivate": { + "default": false, + "type": "boolean" + } + }, + "required": [ + "uid", + "title", + "description", + "slug", + "namespace", + "isPrivate" + ], + "additionalProperties": false + }, + "theme": { + "type": "object", + "properties": { + "uid": { + "$ref": "#/components/schemas/nanoid" + }, + "name": { + "type": "string" + }, + "description": { + "type": "string" + }, + "slug": { + "$ref": "#/components/schemas/slug" + } + }, + "required": [ + "uid", + "name", + "description", + "slug" + ], + "additionalProperties": false + }, + "team": { + "type": "object", + "properties": { + "uid": { + "$ref": "#/components/schemas/nanoid" + }, + "name": { + "$ref": "#/components/schemas/team-name" + }, + "imageUri": { + "$ref": "#/components/schemas/team-image" + }, + "slug": { + "$ref": "#/components/schemas/slug" + }, + "theme": { + "type": "string" + } + }, + "required": [ + "uid", + "name", + "slug", + "theme" + ], + "additionalProperties": false + }, + "team-name": { + "type": "string" + }, + "team-image": { + "type": "string" + }, + "github-project": { + "type": "object", + "properties": { + "uid": { + "default": "nanoid()", + "$ref": "#/components/schemas/nanoid" + }, + "createdAt": { + "default": "unixTimestamp()", + "$ref": "#/components/schemas/timestamp" + }, + "updatedAt": { + "default": "unixTimestamp()", + "$ref": "#/components/schemas/timestamp" + }, + "name": { + "type": "string" + }, + "activeDeployment": { + "default": null, + "anyOf": [ + { + "$ref": "#/components/schemas/active-deployment" + }, + { + "type": "null" + } + ] + }, + "lastPublished": { + "default": null, + "anyOf": [ + { + "$ref": "#/components/schemas/timestamp" + }, + { + "type": "null" + } + ] + }, + "lastPublishedUid": { + "default": null, + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ] + }, + "loginPortalUid": { + "default": "", + "type": "string" + }, + "activeThemeId": { + "default": "", + "type": "string" + }, + "typesenseId": { + "type": "number" + }, + "isPrivate": { + "default": false, + "type": "boolean" + }, + "agentEnabled": { + "default": false, + "type": "boolean" + }, + "accessGroups": { + "default": [] + }, + "slug": { + "$ref": "#/components/schemas/slug" + }, + "publishStatus": { + "default": "", + "type": "string" + }, + "publishMessage": { + "default": "", + "type": "string" + }, + "repository": { + "anyOf": [ + { + "$ref": "#/components/schemas/github-project-repository" + }, + { + "type": "null" + } + ] + } + }, + "required": [ + "uid", + "createdAt", + "updatedAt", + "name", + "activeDeployment", + "lastPublished", + "lastPublishedUid", + "loginPortalUid", + "activeThemeId", + "isPrivate", + "agentEnabled", + "accessGroups", + "slug", + "publishStatus", + "publishMessage" + ], + "additionalProperties": false + }, + "active-deployment": { + "type": "object", + "properties": { + "uid": { + "type": "string" + }, + "domain": { + "type": "string" + }, + "publishedAt": { + "$ref": "#/components/schemas/timestamp" + } + }, + "required": [ + "uid", + "domain", + "publishedAt" + ], + "additionalProperties": false + }, + "github-project-repository": { + "type": "object", + "properties": { + "linkedBy": { + "type": "string" + }, + "id": { + "type": "number" + }, + "name": { + "type": "string", + "minLength": 2 + }, + "configPath": { + "default": "", + "type": "string" + }, + "branch": { + "default": "", + "type": "string" + }, + "publishOnMerge": { + "default": false, + "type": "boolean" + }, + "publishPreviews": { + "default": false, + "type": "boolean" + }, + "prComments": { + "default": false, + "type": "boolean" + }, + "expired": { + "default": false, + "type": "boolean" + } + }, + "required": [ + "linkedBy", + "id", + "name", + "configPath", + "branch", + "publishOnMerge", + "publishPreviews", + "prComments", + "expired" + ], + "additionalProperties": false + }, + "email": { + "type": "string", + "format": "email", + "pattern": "^(?!\\.)(?!.*\\.\\.)([A-Za-z0-9_'+\\-\\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$" + }, + "team-summary": { + "type": "object", + "properties": { + "uid": { + "$ref": "#/components/schemas/nanoid" + }, + "name": { + "$ref": "#/components/schemas/team-name" + }, + "imageUri": { + "$ref": "#/components/schemas/team-image" + } + }, + "required": [ + "uid", + "name" + ], + "additionalProperties": false + }, + "user": { + "type": "object", + "properties": { + "uid": { + "default": "nanoid()", + "$ref": "#/components/schemas/nanoid" + }, + "createdAt": { + "default": "unixTimestamp()", + "$ref": "#/components/schemas/timestamp" + }, + "updatedAt": { + "default": "unixTimestamp()", + "$ref": "#/components/schemas/timestamp" + }, + "email": { + "$ref": "#/components/schemas/email" + }, + "theme": { + "type": "string" + }, + "activeTeamId": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ] + }, + "hasGithub": { + "default": false, + "type": "boolean" + }, + "teams": { + "type": "array", + "items": { + "$ref": "#/components/schemas/team-summary" + } + } + }, + "required": [ + "uid", + "createdAt", + "updatedAt", + "email", + "activeTeamId", + "hasGithub", + "teams" + ], + "additionalProperties": false + } + } + }, + "security": [ + { + "BearerAuth": [] + } + ], + "paths": { + "/v1/apis": { + "get": { + "tags": [ + "Registry" + ], + "description": "List all API documents across every namespace the caller can access.", + "summary": "List all API Documents", + "operationId": "listAllApiDocuments", + "responses": { + "200": { + "description": "Default Response", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/api-document" + } + } + } + } + }, + "400": { + "description": "Bad request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/400" + } + } + } + }, + "401": { + "description": "No auth", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/401" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/403" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/404" + } + } + } + }, + "422": { + "description": "Invalid payload", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/422" + } + } + } + }, + "500": { + "description": "Uncaught error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/500" + } + } + } + } + }, + "x-codeSamples": [ + { + "label": "TypeScript", + "lang": "TypeScript", + "source": "import ScalarAPI from \"@scalar/sdk\";\n\nconst client = new ScalarAPI({\n bearerAuth: process.env[\"BEARER_AUTH\"], // defaults to the BEARER_AUTH env var\n environment: \"production\",\n});\n\nconst listAllAPIDocuments = await client.registry.listAllAPIDocuments();\nconsole.log(listAllAPIDocuments);" + }, + { + "label": "Shell", + "lang": "Shell", + "source": "scalarapi registry list-all-api-documents --bearer-auth \"$BEARER_AUTH\"" + }, + { + "label": "Python", + "lang": "Python", + "source": "import os\n\nfrom scalar_api import ScalarApi\n\nclient = ScalarApi(\n bearer_auth=os.environ.get(\"BEARER_AUTH\"),\n)\n\nregistry = client.registry.list_all_api_documents()\nprint(registry)" + }, + { + "label": "Go", + "lang": "Go", + "source": "package main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"os\"\n\n\tsdk \"scalar-api\"\n\t\"scalar-api/option\"\n)\n\nfunc main() {\n\tclient := sdk.NewClient(\n\t\toption.WithBearerAuth(os.Getenv(\"BEARER_AUTH\")),\n\t)\n\n\tregistry, err := client.Registry.ListAllAPIDocuments(context.Background())\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tfmt.Println(registry)\n}" + }, + { + "label": "Kotlin", + "lang": "Kotlin", + "source": "import com.scalar.api.client.ScalarApiClient\nimport com.scalar.api.client.okhttp.ScalarApiOkHttpClient\nimport com.scalar.api.models.registry.RegistryListAllApiDocumentsParams\n\nval client: ScalarApiClient = ScalarApiOkHttpClient.builder()\n .bearerAuth(System.getenv(\"BEARER_AUTH\"))\n .build()\n\nval registry = client.registry().listAllApiDocuments(RegistryListAllApiDocumentsParams.none())\nprintln(registry)" + }, + { + "label": "Ruby", + "lang": "Ruby", + "source": "require \"json\"\nrequire \"scalar-api\"\n\nclient = ScalarApi::Client.new(\n bearer_auth: ENV[\"BEARER_AUTH\"],\n)\n\nresponse = client.registry.list_all_api_documents\nputs response.inspect" + }, + { + "label": "Java", + "lang": "Java", + "source": "import com.scalar.api.client.ScalarApiClient;\nimport com.scalar.api.client.okhttp.ScalarApiOkHttpClient;\nimport com.scalar.api.models.registry.RegistryListAllApiDocumentsParams;\n\nScalarApiClient client = ScalarApiOkHttpClient.builder()\n .bearerAuth(System.getenv(\"BEARER_AUTH\"))\n .build();\n\nvar registry = client.registry().listAllApiDocuments();\nSystem.out.println(registry);" + }, + { + "lang": "Shell", + "label": "CLI", + "source": "scalarapi registry list-all-api-documents --bearer-auth \"$BEARER_AUTH\"" + } + ] + } + }, + "/v1/apis/{namespace}": { + "get": { + "tags": [ + "Registry" + ], + "description": "List API documents in a namespace.", + "summary": "List API Documents in a namespace", + "operationId": "listApiDocuments", + "responses": { + "200": { + "description": "Default Response", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/api-document" + } + } + } + } + }, + "400": { + "description": "Bad request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/400" + } + } + } + }, + "401": { + "description": "No auth", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/401" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/403" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/404" + } + } + } + }, + "422": { + "description": "Invalid payload", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/422" + } + } + } + }, + "500": { + "description": "Uncaught error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/500" + } + } + } + } + }, + "parameters": [ + { + "schema": { + "type": "string" + }, + "in": "path", + "name": "namespace", + "required": true + } + ], + "x-codeSamples": [ + { + "label": "TypeScript", + "lang": "TypeScript", + "source": "import ScalarAPI from \"@scalar/sdk\";\n\nconst client = new ScalarAPI({\n bearerAuth: process.env[\"BEARER_AUTH\"], // defaults to the BEARER_AUTH env var\n environment: \"production\",\n});\n\nconst listAPIDocuments = await client.registry.listAPIDocuments(\"namespace\");\nconsole.log(listAPIDocuments);" + }, + { + "label": "Shell", + "lang": "Shell", + "source": "scalarapi registry list-api-documents 'namespace' --bearer-auth \"$BEARER_AUTH\"" + }, + { + "label": "Python", + "lang": "Python", + "source": "import os\n\nfrom scalar_api import ScalarApi\n\nclient = ScalarApi(\n bearer_auth=os.environ.get(\"BEARER_AUTH\"),\n)\n\nregistry = client.registry.list_api_documents(\n namespace=\"namespace\",\n)\nprint(registry)" + }, + { + "label": "Go", + "lang": "Go", + "source": "package main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"os\"\n\n\tsdk \"scalar-api\"\n\t\"scalar-api/option\"\n)\n\nfunc main() {\n\tclient := sdk.NewClient(\n\t\toption.WithBearerAuth(os.Getenv(\"BEARER_AUTH\")),\n\t)\n\n\tregistry, err := client.Registry.ListAPIDocuments(context.Background(), \"namespace\")\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tfmt.Println(registry)\n}" + }, + { + "label": "Kotlin", + "lang": "Kotlin", + "source": "import com.scalar.api.client.ScalarApiClient\nimport com.scalar.api.client.okhttp.ScalarApiOkHttpClient\nimport com.scalar.api.models.registry.RegistryListApiDocumentsParams\n\nval client: ScalarApiClient = ScalarApiOkHttpClient.builder()\n .bearerAuth(System.getenv(\"BEARER_AUTH\"))\n .build()\n\nval params = RegistryListApiDocumentsParams.builder()\n .namespace(\"namespace\")\n .build()\nval registry = client.registry().listApiDocuments(params)\nprintln(registry)" + }, + { + "label": "Ruby", + "lang": "Ruby", + "source": "require \"json\"\nrequire \"scalar-api\"\n\nclient = ScalarApi::Client.new(\n bearer_auth: ENV[\"BEARER_AUTH\"],\n)\n\nresponse = client.registry.list_api_documents(\"smoke-test\")\nputs response.inspect" + }, + { + "label": "Java", + "lang": "Java", + "source": "import com.scalar.api.client.ScalarApiClient;\nimport com.scalar.api.client.okhttp.ScalarApiOkHttpClient;\nimport com.scalar.api.models.registry.RegistryListApiDocumentsParams;\n\nScalarApiClient client = ScalarApiOkHttpClient.builder()\n .bearerAuth(System.getenv(\"BEARER_AUTH\"))\n .build();\n\nRegistryListApiDocumentsParams params = RegistryListApiDocumentsParams.builder()\n .namespace(\"namespace\")\n .build();\nvar registry = client.registry().listApiDocuments(params);\nSystem.out.println(registry);" + }, + { + "lang": "Shell", + "label": "CLI", + "source": "scalarapi registry list-api-documents 'namespace' --bearer-auth \"$BEARER_AUTH\"" + } + ] + }, + "post": { + "tags": [ + "Registry" + ], + "description": "Create an API document.", + "summary": "Create API Document", + "operationId": "createApiDocument", + "responses": { + "200": { + "description": "Default Response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "uid": { + "type": "string" + }, + "versionUid": { + "type": "string" + }, + "title": { + "type": "string" + }, + "jsonSha": { + "type": "string" + }, + "yamlSha": { + "type": "string" + }, + "versionSha": { + "type": "string" + } + }, + "required": [ + "uid", + "versionUid", + "title", + "jsonSha", + "yamlSha", + "versionSha" + ], + "additionalProperties": false + } + } + } + }, + "400": { + "description": "Bad request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/400" + } + } + } + }, + "401": { + "description": "No auth", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/401" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/403" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/404" + } + } + } + }, + "422": { + "description": "Invalid payload", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/422" + } + } + } + }, + "500": { + "description": "Uncaught error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/500" + } + } + } + } + }, + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "title": { + "type": "string" + }, + "description": { + "type": "string" + }, + "version": { + "$ref": "#/components/schemas/version" + }, + "slug": { + "type": "string" + }, + "ruleset": { + "type": "string" + }, + "isPrivate": { + "type": "boolean" + }, + "document": { + "type": "string" + } + }, + "required": [ + "title", + "version", + "slug", + "document" + ], + "additionalProperties": false + } + } + }, + "required": true + }, + "parameters": [ + { + "schema": { + "type": "string" + }, + "in": "path", + "name": "namespace", + "required": true + } + ], + "x-codeSamples": [ + { + "label": "TypeScript", + "lang": "TypeScript", + "source": "import ScalarAPI from \"@scalar/sdk\";\n\nconst client = new ScalarAPI({\n bearerAuth: process.env[\"BEARER_AUTH\"], // defaults to the BEARER_AUTH env var\n environment: \"production\",\n});\n\nconst createAPIDocument = await client.registry.createAPIDocument(\"namespace\", {\n title: \"\",\n version: \"\",\n slug: \"\",\n document: \"\",\n});\nconsole.log(createAPIDocument);" + }, + { + "label": "Shell", + "lang": "Shell", + "source": "scalarapi registry create-api-document 'namespace' --bearer-auth \"$BEARER_AUTH\" --title 'title' --version-command 'version' --slug 'slug' --document 'document'" + }, + { + "label": "Python", + "lang": "Python", + "source": "import os\n\nfrom scalar_api import ScalarApi\n\nclient = ScalarApi(\n bearer_auth=os.environ.get(\"BEARER_AUTH\"),\n)\n\nregistry = client.registry.create_api_document(\n namespace=\"namespace\",\n title=\"\",\n version=\"\",\n slug=\"\",\n document=\"\",\n idempotency_key=\"\",\n)\nprint(registry)" + }, + { + "label": "Go", + "lang": "Go", + "source": "package main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"os\"\n\n\tsdk \"scalar-api\"\n\t\"scalar-api/option\"\n)\n\nfunc main() {\n\tclient := sdk.NewClient(\n\t\toption.WithBearerAuth(os.Getenv(\"BEARER_AUTH\")),\n\t)\n\n\tregistry, err := client.Registry.NewAPIDocument(context.Background(), \"namespace\", sdk.RegistryNewAPIDocumentParams{\n\t\tDocument: \"\",\n\t\tSlug: \"\",\n\t\tTitle: \"\",\n\t\tVersion: \"\",\n\t})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tfmt.Println(registry)\n}" + }, + { + "label": "Kotlin", + "lang": "Kotlin", + "source": "import com.scalar.api.client.ScalarApiClient\nimport com.scalar.api.client.okhttp.ScalarApiOkHttpClient\nimport com.scalar.api.models.registry.RegistryCreateApiDocumentParams\n\nval client: ScalarApiClient = ScalarApiOkHttpClient.builder()\n .bearerAuth(System.getenv(\"BEARER_AUTH\"))\n .build()\n\nval params = RegistryCreateApiDocumentParams.builder()\n .namespace(\"namespace\")\n .title(\"title\")\n .version(\"version\")\n .slug(\"slug\")\n .document(\"document\")\n .build()\nval registry = client.registry().createApiDocument(params)\nprintln(registry)" + }, + { + "label": "Ruby", + "lang": "Ruby", + "source": "require \"json\"\nrequire \"scalar-api\"\n\nclient = ScalarApi::Client.new(\n bearer_auth: ENV[\"BEARER_AUTH\"],\n)\n\nresponse = client.registry.create_api_document(\"smoke-test\", { title: \"title\", description: \"description\", version: \"version\", slug: \"slug\", ruleset: \"ruleset\", is_private: \"is_private\", document: \"document\" })\nputs response.inspect" + }, + { + "label": "Java", + "lang": "Java", + "source": "import com.scalar.api.client.ScalarApiClient;\nimport com.scalar.api.client.okhttp.ScalarApiOkHttpClient;\nimport com.scalar.api.models.registry.RegistryCreateApiDocumentParams;\n\nScalarApiClient client = ScalarApiOkHttpClient.builder()\n .bearerAuth(System.getenv(\"BEARER_AUTH\"))\n .build();\n\nRegistryCreateApiDocumentParams params = RegistryCreateApiDocumentParams.builder()\n .namespace(\"namespace\")\n .title(\"title\")\n .version(\"version\")\n .slug(\"slug\")\n .document(\"document\")\n .build();\nvar registry = client.registry().createApiDocument(params);\nSystem.out.println(registry);" + }, + { + "lang": "Shell", + "label": "CLI", + "source": "scalarapi registry create-api-document 'namespace' --bearer-auth \"$BEARER_AUTH\" --title 'title' --version-command 'version' --slug 'slug' --document 'document'" + } + ] + } + }, + "/v1/apis/{namespace}/{slug}": { + "patch": { + "tags": [ + "Registry" + ], + "description": "Update metadata for an API document.", + "summary": "Update API Document metadata", + "operationId": "updateApiDocument", + "responses": { + "200": { + "description": "Default Response", + "content": { + "application/json": { + "schema": { + "type": "null" + } + } + } + }, + "400": { + "description": "Bad request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/400" + } + } + } + }, + "401": { + "description": "No auth", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/401" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/403" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/404" + } + } + } + }, + "422": { + "description": "Invalid payload", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/422" + } + } + } + }, + "500": { + "description": "Uncaught error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/500" + } + } + } + } + }, + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "title": { + "type": "string" + }, + "description": { + "type": "string" + }, + "isPrivate": { + "type": "boolean" + }, + "ruleset": { + "type": "string" + } + }, + "additionalProperties": false + } + } + }, + "required": true + }, + "parameters": [ + { + "schema": { + "type": "string" + }, + "in": "path", + "name": "namespace", + "required": true + }, + { + "schema": { + "type": "string" + }, + "in": "path", + "name": "slug", + "required": true + } + ], + "x-codeSamples": [ + { + "label": "TypeScript", + "lang": "TypeScript", + "source": "import ScalarAPI from \"@scalar/sdk\";\n\nconst client = new ScalarAPI({\n bearerAuth: process.env[\"BEARER_AUTH\"], // defaults to the BEARER_AUTH env var\n environment: \"production\",\n});\n\nawait client.registry.updateAPIDocument(\"slug\", {\n namespace: \"namespace\",\n});" + }, + { + "label": "Shell", + "lang": "Shell", + "source": "scalarapi registry update-api-document 'slug' --bearer-auth \"$BEARER_AUTH\" --namespace 'namespace'" + }, + { + "label": "Python", + "lang": "Python", + "source": "import os\n\nfrom scalar_api import ScalarApi\n\nclient = ScalarApi(\n bearer_auth=os.environ.get(\"BEARER_AUTH\"),\n)\n\nregistry = client.registry.update_api_document(\n namespace=\"namespace\",\n slug=\"slug\",\n idempotency_key=\"\",\n)\nprint(registry)" + }, + { + "label": "Go", + "lang": "Go", + "source": "package main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"os\"\n\n\tsdk \"scalar-api\"\n\t\"scalar-api/option\"\n)\n\nfunc main() {\n\tclient := sdk.NewClient(\n\t\toption.WithBearerAuth(os.Getenv(\"BEARER_AUTH\")),\n\t)\n\n\tregistry, err := client.Registry.UpdateAPIDocument(context.Background(), \"namespace\", \"slug\", sdk.RegistryUpdateAPIDocumentParams{})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tfmt.Println(registry)\n}" + }, + { + "label": "Kotlin", + "lang": "Kotlin", + "source": "import com.scalar.api.client.ScalarApiClient\nimport com.scalar.api.client.okhttp.ScalarApiOkHttpClient\nimport com.scalar.api.models.registry.RegistryUpdateApiDocumentParams\n\nval client: ScalarApiClient = ScalarApiOkHttpClient.builder()\n .bearerAuth(System.getenv(\"BEARER_AUTH\"))\n .build()\n\nval params = RegistryUpdateApiDocumentParams.builder()\n .namespace(\"namespace\")\n .slug(\"slug\")\n .build()\nval registry = client.registry().updateApiDocument(params)\nprintln(registry)" + }, + { + "label": "Ruby", + "lang": "Ruby", + "source": "require \"json\"\nrequire \"scalar-api\"\n\nclient = ScalarApi::Client.new(\n bearer_auth: ENV[\"BEARER_AUTH\"],\n)\n\nresponse = client.registry.update_api_document(\"smoke-test\", { namespace: \"namespace\", title: \"title\", description: \"description\", is_private: \"is_private\", ruleset: \"ruleset\" })\nputs response.inspect" + }, + { + "label": "Java", + "lang": "Java", + "source": "import com.scalar.api.client.ScalarApiClient;\nimport com.scalar.api.client.okhttp.ScalarApiOkHttpClient;\nimport com.scalar.api.models.registry.RegistryUpdateApiDocumentParams;\n\nScalarApiClient client = ScalarApiOkHttpClient.builder()\n .bearerAuth(System.getenv(\"BEARER_AUTH\"))\n .build();\n\nRegistryUpdateApiDocumentParams params = RegistryUpdateApiDocumentParams.builder()\n .namespace(\"namespace\")\n .slug(\"slug\")\n .build();\nvar registry = client.registry().updateApiDocument(params);\nSystem.out.println(registry);" + }, + { + "lang": "Shell", + "label": "CLI", + "source": "scalarapi registry update-api-document 'slug' --bearer-auth \"$BEARER_AUTH\" --namespace 'namespace'" + } + ] + }, + "delete": { + "tags": [ + "Registry" + ], + "description": "Delete an API document and all versions.", + "summary": "Delete API Document", + "operationId": "deleteApiDocument", + "responses": { + "200": { + "description": "Default Response", + "content": { + "application/json": { + "schema": { + "type": "null" + } + } + } + }, + "400": { + "description": "Bad request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/400" + } + } + } + }, + "401": { + "description": "No auth", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/401" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/403" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/404" + } + } + } + }, + "422": { + "description": "Invalid payload", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/422" + } + } + } + }, + "500": { + "description": "Uncaught error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/500" + } + } + } + } + }, + "parameters": [ + { + "schema": { + "type": "string" + }, + "in": "path", + "name": "namespace", + "required": true + }, + { + "schema": { + "type": "string" + }, + "in": "path", + "name": "slug", + "required": true + } + ], + "x-codeSamples": [ + { + "label": "TypeScript", + "lang": "TypeScript", + "source": "import ScalarAPI from \"@scalar/sdk\";\n\nconst client = new ScalarAPI({\n bearerAuth: process.env[\"BEARER_AUTH\"], // defaults to the BEARER_AUTH env var\n environment: \"production\",\n});\n\nawait client.registry.deleteAPIDocument(\"slug\", {\n namespace: \"namespace\",\n});" + }, + { + "label": "Shell", + "lang": "Shell", + "source": "scalarapi registry delete-api-document 'slug' --bearer-auth \"$BEARER_AUTH\" --namespace 'namespace'" + }, + { + "label": "Python", + "lang": "Python", + "source": "import os\n\nfrom scalar_api import ScalarApi\n\nclient = ScalarApi(\n bearer_auth=os.environ.get(\"BEARER_AUTH\"),\n)\n\nregistry = client.registry.delete_api_document(\n namespace=\"namespace\",\n slug=\"slug\",\n idempotency_key=\"\",\n)\nprint(registry)" + }, + { + "label": "Go", + "lang": "Go", + "source": "package main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"os\"\n\n\tsdk \"scalar-api\"\n\t\"scalar-api/option\"\n)\n\nfunc main() {\n\tclient := sdk.NewClient(\n\t\toption.WithBearerAuth(os.Getenv(\"BEARER_AUTH\")),\n\t)\n\n\tregistry, err := client.Registry.DeleteAPIDocument(context.Background(), \"namespace\", \"slug\")\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tfmt.Println(registry)\n}" + }, + { + "label": "Kotlin", + "lang": "Kotlin", + "source": "import com.scalar.api.client.ScalarApiClient\nimport com.scalar.api.client.okhttp.ScalarApiOkHttpClient\nimport com.scalar.api.models.registry.RegistryDeleteApiDocumentParams\n\nval client: ScalarApiClient = ScalarApiOkHttpClient.builder()\n .bearerAuth(System.getenv(\"BEARER_AUTH\"))\n .build()\n\nval params = RegistryDeleteApiDocumentParams.builder()\n .namespace(\"namespace\")\n .slug(\"slug\")\n .build()\nval registry = client.registry().deleteApiDocument(params)\nprintln(registry)" + }, + { + "label": "Ruby", + "lang": "Ruby", + "source": "require \"json\"\nrequire \"scalar-api\"\n\nclient = ScalarApi::Client.new(\n bearer_auth: ENV[\"BEARER_AUTH\"],\n)\n\nresponse = client.registry.delete_api_document(\"smoke-test\", { namespace: \"namespace\" })\nputs response.inspect" + }, + { + "label": "Java", + "lang": "Java", + "source": "import com.scalar.api.client.ScalarApiClient;\nimport com.scalar.api.client.okhttp.ScalarApiOkHttpClient;\nimport com.scalar.api.models.registry.RegistryDeleteApiDocumentParams;\n\nScalarApiClient client = ScalarApiOkHttpClient.builder()\n .bearerAuth(System.getenv(\"BEARER_AUTH\"))\n .build();\n\nRegistryDeleteApiDocumentParams params = RegistryDeleteApiDocumentParams.builder()\n .namespace(\"namespace\")\n .slug(\"slug\")\n .build();\nvar registry = client.registry().deleteApiDocument(params);\nSystem.out.println(registry);" + }, + { + "lang": "Shell", + "label": "CLI", + "source": "scalarapi registry delete-api-document 'slug' --bearer-auth \"$BEARER_AUTH\" --namespace 'namespace'" + } + ] + } + }, + "/v1/apis/{namespace}/{slug}/version/{semver}": { + "get": { + "tags": [ + "Registry" + ], + "description": "Get a specific API document version.", + "summary": "Get API Document", + "operationId": "getApiDocumentVersion", + "responses": { + "200": { + "description": "Default Response", + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + } + }, + "400": { + "description": "Bad request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/400" + } + } + } + }, + "401": { + "description": "No auth", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/401" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/403" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/404" + } + } + } + }, + "422": { + "description": "Invalid payload", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/422" + } + } + } + }, + "500": { + "description": "Uncaught error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/500" + } + } + } + } + }, + "parameters": [ + { + "schema": { + "type": "string" + }, + "in": "path", + "name": "namespace", + "required": true + }, + { + "schema": { + "type": "string" + }, + "in": "path", + "name": "slug", + "required": true + }, + { + "schema": { + "type": "string" + }, + "in": "path", + "name": "semver", + "required": true + } + ], + "x-codeSamples": [ + { + "label": "TypeScript", + "lang": "TypeScript", + "source": "import ScalarAPI from \"@scalar/sdk\";\n\nconst client = new ScalarAPI({\n bearerAuth: process.env[\"BEARER_AUTH\"], // defaults to the BEARER_AUTH env var\n environment: \"production\",\n});\n\nconst string_ = await client.registry.retrieveAPIDocumentVersion(\"semver\", {\n namespace: \"namespace\",\n slug: \"slug\",\n});\nconsole.log(string_);" + }, + { + "label": "Shell", + "lang": "Shell", + "source": "scalarapi registry retrieve-api-document-version 'semver' --bearer-auth \"$BEARER_AUTH\" --namespace 'namespace' --slug 'slug'" + }, + { + "label": "Python", + "lang": "Python", + "source": "import os\n\nfrom scalar_api import ScalarApi\n\nclient = ScalarApi(\n bearer_auth=os.environ.get(\"BEARER_AUTH\"),\n)\n\nregistry = client.registry.retrieve_api_document_version(\n namespace=\"namespace\",\n slug=\"slug\",\n semver=\"semver\",\n)\nprint(registry)" + }, + { + "label": "Go", + "lang": "Go", + "source": "package main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"os\"\n\n\tsdk \"scalar-api\"\n\t\"scalar-api/option\"\n)\n\nfunc main() {\n\tclient := sdk.NewClient(\n\t\toption.WithBearerAuth(os.Getenv(\"BEARER_AUTH\")),\n\t)\n\n\tregistry, err := client.Registry.GetAPIDocumentVersion(context.Background(), \"namespace\", \"slug\", \"semver\")\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tfmt.Println(registry)\n}" + }, + { + "label": "Kotlin", + "lang": "Kotlin", + "source": "import com.scalar.api.client.ScalarApiClient\nimport com.scalar.api.client.okhttp.ScalarApiOkHttpClient\nimport com.scalar.api.models.registry.RegistryRetrieveApiDocumentVersionParams\n\nval client: ScalarApiClient = ScalarApiOkHttpClient.builder()\n .bearerAuth(System.getenv(\"BEARER_AUTH\"))\n .build()\n\nval params = RegistryRetrieveApiDocumentVersionParams.builder()\n .namespace(\"namespace\")\n .slug(\"slug\")\n .semver(\"semver\")\n .build()\nval registry = client.registry().retrieveApiDocumentVersion(params)\nprintln(registry)" + }, + { + "label": "Ruby", + "lang": "Ruby", + "source": "require \"json\"\nrequire \"scalar-api\"\n\nclient = ScalarApi::Client.new(\n bearer_auth: ENV[\"BEARER_AUTH\"],\n)\n\nresponse = client.registry.retrieve_api_document_version(\"smoke-test\", { namespace: \"namespace\", slug: \"slug\" })\nputs response.inspect" + }, + { + "label": "Java", + "lang": "Java", + "source": "import com.scalar.api.client.ScalarApiClient;\nimport com.scalar.api.client.okhttp.ScalarApiOkHttpClient;\nimport com.scalar.api.models.registry.RegistryRetrieveApiDocumentVersionParams;\n\nScalarApiClient client = ScalarApiOkHttpClient.builder()\n .bearerAuth(System.getenv(\"BEARER_AUTH\"))\n .build();\n\nRegistryRetrieveApiDocumentVersionParams params = RegistryRetrieveApiDocumentVersionParams.builder()\n .namespace(\"namespace\")\n .slug(\"slug\")\n .semver(\"semver\")\n .build();\nvar registry = client.registry().retrieveApiDocumentVersion(params);\nSystem.out.println(registry);" + }, + { + "lang": "Shell", + "label": "CLI", + "source": "scalarapi registry retrieve-api-document-version 'semver' --bearer-auth \"$BEARER_AUTH\" --namespace 'namespace' --slug 'slug'" + } + ] + }, + "patch": { + "tags": [ + "Registry" + ], + "description": "Update the registry file content for an API document version.", + "summary": "Update API Document version", + "operationId": "updateApiDocumentVersion", + "responses": { + "200": { + "description": "Default Response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "jsonSha": { + "type": "string" + }, + "yamlSha": { + "type": "string" + }, + "versionSha": { + "type": "string" + } + }, + "required": [ + "jsonSha", + "yamlSha", + "versionSha" + ], + "additionalProperties": false + } + } + } + }, + "400": { + "description": "Bad request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/400" + } + } + } + }, + "401": { + "description": "No auth", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/401" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/403" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/404" + } + } + } + }, + "422": { + "description": "Invalid payload", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/422" + } + } + } + }, + "500": { + "description": "Uncaught error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/500" + } + } + } + } + }, + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "document": { + "type": "string" + }, + "lastKnownVersionSha": { + "type": "string" + } + }, + "required": [ + "document" + ], + "additionalProperties": false + } + } + }, + "required": true + }, + "parameters": [ + { + "schema": { + "type": "string" + }, + "in": "path", + "name": "namespace", + "required": true + }, + { + "schema": { + "type": "string" + }, + "in": "path", + "name": "slug", + "required": true + }, + { + "schema": { + "type": "string" + }, + "in": "path", + "name": "semver", + "required": true + } + ], + "x-codeSamples": [ + { + "label": "TypeScript", + "lang": "TypeScript", + "source": "import ScalarAPI from \"@scalar/sdk\";\n\nconst client = new ScalarAPI({\n bearerAuth: process.env[\"BEARER_AUTH\"], // defaults to the BEARER_AUTH env var\n environment: \"production\",\n});\n\nconst updateAPIDocumentVersion = await client.registry.updateAPIDocumentVersion(\"semver\", {\n namespace: \"namespace\",\n slug: \"slug\",\n document: \"\",\n});\nconsole.log(updateAPIDocumentVersion);" + }, + { + "label": "Shell", + "lang": "Shell", + "source": "scalarapi registry update-api-document-version 'semver' --bearer-auth \"$BEARER_AUTH\" --namespace 'namespace' --slug 'slug' --document 'document'" + }, + { + "label": "Python", + "lang": "Python", + "source": "import os\n\nfrom scalar_api import ScalarApi\n\nclient = ScalarApi(\n bearer_auth=os.environ.get(\"BEARER_AUTH\"),\n)\n\nregistry = client.registry.update_api_document_version(\n namespace=\"namespace\",\n slug=\"slug\",\n semver=\"semver\",\n document=\"\",\n idempotency_key=\"\",\n)\nprint(registry)" + }, + { + "label": "Go", + "lang": "Go", + "source": "package main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"os\"\n\n\tsdk \"scalar-api\"\n\t\"scalar-api/option\"\n)\n\nfunc main() {\n\tclient := sdk.NewClient(\n\t\toption.WithBearerAuth(os.Getenv(\"BEARER_AUTH\")),\n\t)\n\n\tregistry, err := client.Registry.UpdateAPIDocumentVersion(context.Background(), \"namespace\", \"slug\", \"semver\", sdk.RegistryUpdateAPIDocumentVersionParams{\n\t\tDocument: \"\",\n\t})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tfmt.Println(registry)\n}" + }, + { + "label": "Kotlin", + "lang": "Kotlin", + "source": "import com.scalar.api.client.ScalarApiClient\nimport com.scalar.api.client.okhttp.ScalarApiOkHttpClient\nimport com.scalar.api.models.registry.RegistryUpdateApiDocumentVersionParams\n\nval client: ScalarApiClient = ScalarApiOkHttpClient.builder()\n .bearerAuth(System.getenv(\"BEARER_AUTH\"))\n .build()\n\nval params = RegistryUpdateApiDocumentVersionParams.builder()\n .namespace(\"namespace\")\n .slug(\"slug\")\n .semver(\"semver\")\n .document(\"document\")\n .build()\nval registry = client.registry().updateApiDocumentVersion(params)\nprintln(registry)" + }, + { + "label": "Ruby", + "lang": "Ruby", + "source": "require \"json\"\nrequire \"scalar-api\"\n\nclient = ScalarApi::Client.new(\n bearer_auth: ENV[\"BEARER_AUTH\"],\n)\n\nresponse = client.registry.update_api_document_version(\"smoke-test\", { namespace: \"namespace\", slug: \"slug\", document: \"document\", last_known_version_sha: \"last_known_version_sha\" })\nputs response.inspect" + }, + { + "label": "Java", + "lang": "Java", + "source": "import com.scalar.api.client.ScalarApiClient;\nimport com.scalar.api.client.okhttp.ScalarApiOkHttpClient;\nimport com.scalar.api.models.registry.RegistryUpdateApiDocumentVersionParams;\n\nScalarApiClient client = ScalarApiOkHttpClient.builder()\n .bearerAuth(System.getenv(\"BEARER_AUTH\"))\n .build();\n\nRegistryUpdateApiDocumentVersionParams params = RegistryUpdateApiDocumentVersionParams.builder()\n .namespace(\"namespace\")\n .slug(\"slug\")\n .semver(\"semver\")\n .document(\"document\")\n .build();\nvar registry = client.registry().updateApiDocumentVersion(params);\nSystem.out.println(registry);" + }, + { + "lang": "Shell", + "label": "CLI", + "source": "scalarapi registry update-api-document-version 'semver' --bearer-auth \"$BEARER_AUTH\" --namespace 'namespace' --slug 'slug' --document 'document'" + } + ] + }, + "delete": { + "tags": [ + "Registry" + ], + "description": "Delete a specific API document version.", + "summary": "Delete API Document version", + "operationId": "deleteApiDocumentVersion", + "responses": { + "200": { + "description": "Default Response", + "content": { + "application/json": { + "schema": { + "type": "null" + } + } + } + }, + "400": { + "description": "Bad request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/400" + } + } + } + }, + "401": { + "description": "No auth", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/401" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/403" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/404" + } + } + } + }, + "422": { + "description": "Invalid payload", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/422" + } + } + } + }, + "500": { + "description": "Uncaught error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/500" + } + } + } + } + }, + "parameters": [ + { + "schema": { + "type": "string" + }, + "in": "path", + "name": "namespace", + "required": true + }, + { + "schema": { + "type": "string" + }, + "in": "path", + "name": "slug", + "required": true + }, + { + "schema": { + "type": "string" + }, + "in": "path", + "name": "semver", + "required": true + } + ], + "x-codeSamples": [ + { + "label": "TypeScript", + "lang": "TypeScript", + "source": "import ScalarAPI from \"@scalar/sdk\";\n\nconst client = new ScalarAPI({\n bearerAuth: process.env[\"BEARER_AUTH\"], // defaults to the BEARER_AUTH env var\n environment: \"production\",\n});\n\nawait client.registry.deleteAPIDocumentVersion(\"semver\", {\n namespace: \"namespace\",\n slug: \"slug\",\n});" + }, + { + "label": "Shell", + "lang": "Shell", + "source": "scalarapi registry delete-api-document-version 'semver' --bearer-auth \"$BEARER_AUTH\" --namespace 'namespace' --slug 'slug'" + }, + { + "label": "Python", + "lang": "Python", + "source": "import os\n\nfrom scalar_api import ScalarApi\n\nclient = ScalarApi(\n bearer_auth=os.environ.get(\"BEARER_AUTH\"),\n)\n\nregistry = client.registry.delete_api_document_version(\n namespace=\"namespace\",\n slug=\"slug\",\n semver=\"semver\",\n idempotency_key=\"\",\n)\nprint(registry)" + }, + { + "label": "Go", + "lang": "Go", + "source": "package main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"os\"\n\n\tsdk \"scalar-api\"\n\t\"scalar-api/option\"\n)\n\nfunc main() {\n\tclient := sdk.NewClient(\n\t\toption.WithBearerAuth(os.Getenv(\"BEARER_AUTH\")),\n\t)\n\n\tregistry, err := client.Registry.DeleteAPIDocumentVersion(context.Background(), \"namespace\", \"slug\", \"semver\")\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tfmt.Println(registry)\n}" + }, + { + "label": "Kotlin", + "lang": "Kotlin", + "source": "import com.scalar.api.client.ScalarApiClient\nimport com.scalar.api.client.okhttp.ScalarApiOkHttpClient\nimport com.scalar.api.models.registry.RegistryDeleteApiDocumentVersionParams\n\nval client: ScalarApiClient = ScalarApiOkHttpClient.builder()\n .bearerAuth(System.getenv(\"BEARER_AUTH\"))\n .build()\n\nval params = RegistryDeleteApiDocumentVersionParams.builder()\n .namespace(\"namespace\")\n .slug(\"slug\")\n .semver(\"semver\")\n .build()\nval registry = client.registry().deleteApiDocumentVersion(params)\nprintln(registry)" + }, + { + "label": "Ruby", + "lang": "Ruby", + "source": "require \"json\"\nrequire \"scalar-api\"\n\nclient = ScalarApi::Client.new(\n bearer_auth: ENV[\"BEARER_AUTH\"],\n)\n\nresponse = client.registry.delete_api_document_version(\"smoke-test\", { namespace: \"namespace\", slug: \"slug\" })\nputs response.inspect" + }, + { + "label": "Java", + "lang": "Java", + "source": "import com.scalar.api.client.ScalarApiClient;\nimport com.scalar.api.client.okhttp.ScalarApiOkHttpClient;\nimport com.scalar.api.models.registry.RegistryDeleteApiDocumentVersionParams;\n\nScalarApiClient client = ScalarApiOkHttpClient.builder()\n .bearerAuth(System.getenv(\"BEARER_AUTH\"))\n .build();\n\nRegistryDeleteApiDocumentVersionParams params = RegistryDeleteApiDocumentVersionParams.builder()\n .namespace(\"namespace\")\n .slug(\"slug\")\n .semver(\"semver\")\n .build();\nvar registry = client.registry().deleteApiDocumentVersion(params);\nSystem.out.println(registry);" + }, + { + "lang": "Shell", + "label": "CLI", + "source": "scalarapi registry delete-api-document-version 'semver' --bearer-auth \"$BEARER_AUTH\" --namespace 'namespace' --slug 'slug'" + } + ] + } + }, + "/v1/apis/{namespace}/{slug}/version/{semver}/metadata": { + "get": { + "tags": [ + "Registry" + ], + "description": "Get metadata (uid, content shas, version sha, tags) for a specific API document version.", + "summary": "Get API Document version metadata", + "operationId": "getApiDocumentVersionMetadata", + "responses": { + "200": { + "description": "Default Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/managed-doc-version" + } + } + } + }, + "400": { + "description": "Bad request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/400" + } + } + } + }, + "401": { + "description": "No auth", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/401" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/403" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/404" + } + } + } + }, + "422": { + "description": "Invalid payload", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/422" + } + } + } + }, + "500": { + "description": "Uncaught error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/500" + } + } + } + } + }, + "parameters": [ + { + "schema": { + "type": "string" + }, + "in": "path", + "name": "namespace", + "required": true + }, + { + "schema": { + "type": "string" + }, + "in": "path", + "name": "slug", + "required": true + }, + { + "schema": { + "type": "string" + }, + "in": "path", + "name": "semver", + "required": true + } + ], + "x-codeSamples": [ + { + "label": "TypeScript", + "lang": "TypeScript", + "source": "import ScalarAPI from \"@scalar/sdk\";\n\nconst client = new ScalarAPI({\n bearerAuth: process.env[\"BEARER_AUTH\"], // defaults to the BEARER_AUTH env var\n environment: \"production\",\n});\n\nconst managedDocVersion = await client.registry.listAPIDocumentVersionMetadata(\"semver\", {\n namespace: \"namespace\",\n slug: \"slug\",\n});\nconsole.log(managedDocVersion);" + }, + { + "label": "Shell", + "lang": "Shell", + "source": "scalarapi registry list-api-document-version-metadata 'semver' --bearer-auth \"$BEARER_AUTH\" --namespace 'namespace' --slug 'slug'" + }, + { + "label": "Python", + "lang": "Python", + "source": "import os\n\nfrom scalar_api import ScalarApi\n\nclient = ScalarApi(\n bearer_auth=os.environ.get(\"BEARER_AUTH\"),\n)\n\nregistry = client.registry.list_api_document_version_metadata(\n namespace=\"namespace\",\n slug=\"slug\",\n semver=\"semver\",\n)\nprint(registry)" + }, + { + "label": "Go", + "lang": "Go", + "source": "package main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"os\"\n\n\tsdk \"scalar-api\"\n\t\"scalar-api/option\"\n)\n\nfunc main() {\n\tclient := sdk.NewClient(\n\t\toption.WithBearerAuth(os.Getenv(\"BEARER_AUTH\")),\n\t)\n\n\tregistry, err := client.Registry.ListAPIDocumentVersionMetadata(context.Background(), \"namespace\", \"slug\", \"semver\")\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tfmt.Println(registry)\n}" + }, + { + "label": "Kotlin", + "lang": "Kotlin", + "source": "import com.scalar.api.client.ScalarApiClient\nimport com.scalar.api.client.okhttp.ScalarApiOkHttpClient\nimport com.scalar.api.models.registry.RegistryListApiDocumentVersionMetadataParams\n\nval client: ScalarApiClient = ScalarApiOkHttpClient.builder()\n .bearerAuth(System.getenv(\"BEARER_AUTH\"))\n .build()\n\nval params = RegistryListApiDocumentVersionMetadataParams.builder()\n .namespace(\"namespace\")\n .slug(\"slug\")\n .semver(\"semver\")\n .build()\nval registry = client.registry().listApiDocumentVersionMetadata(params)\nprintln(registry)" + }, + { + "label": "Ruby", + "lang": "Ruby", + "source": "require \"json\"\nrequire \"scalar-api\"\n\nclient = ScalarApi::Client.new(\n bearer_auth: ENV[\"BEARER_AUTH\"],\n)\n\nresponse = client.registry.list_api_document_version_metadata(\"smoke-test\", { namespace: \"namespace\", slug: \"slug\" })\nputs response.inspect" + }, + { + "label": "Java", + "lang": "Java", + "source": "import com.scalar.api.client.ScalarApiClient;\nimport com.scalar.api.client.okhttp.ScalarApiOkHttpClient;\nimport com.scalar.api.models.registry.RegistryListApiDocumentVersionMetadataParams;\n\nScalarApiClient client = ScalarApiOkHttpClient.builder()\n .bearerAuth(System.getenv(\"BEARER_AUTH\"))\n .build();\n\nRegistryListApiDocumentVersionMetadataParams params = RegistryListApiDocumentVersionMetadataParams.builder()\n .namespace(\"namespace\")\n .slug(\"slug\")\n .semver(\"semver\")\n .build();\nvar registry = client.registry().listApiDocumentVersionMetadata(params);\nSystem.out.println(registry);" + }, + { + "lang": "Shell", + "label": "CLI", + "source": "scalarapi registry list-api-document-version-metadata 'semver' --bearer-auth \"$BEARER_AUTH\" --namespace 'namespace' --slug 'slug'" + } + ] + } + }, + "/v1/apis/{namespace}/{slug}/version": { + "post": { + "tags": [ + "Registry" + ], + "description": "Create a new API document version.", + "summary": "Create API Document version", + "operationId": "createApiDocumentVersion", + "responses": { + "200": { + "description": "Default Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/managed-doc-version" + } + } + } + }, + "400": { + "description": "Bad request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/400" + } + } + } + }, + "401": { + "description": "No auth", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/401" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/403" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/404" + } + } + } + }, + "422": { + "description": "Invalid payload", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/422" + } + } + } + }, + "500": { + "description": "Uncaught error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/500" + } + } + } + } + }, + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "version": { + "$ref": "#/components/schemas/version" + }, + "document": { + "type": "string" + }, + "force": { + "type": "boolean" + }, + "lastKnownVersionSha": { + "type": "string" + } + }, + "required": [ + "version", + "document" + ], + "additionalProperties": false + } + } + }, + "required": true + }, + "parameters": [ + { + "schema": { + "type": "string" + }, + "in": "path", + "name": "namespace", + "required": true + }, + { + "schema": { + "type": "string" + }, + "in": "path", + "name": "slug", + "required": true + } + ], + "x-codeSamples": [ + { + "label": "TypeScript", + "lang": "TypeScript", + "source": "import ScalarAPI from \"@scalar/sdk\";\n\nconst client = new ScalarAPI({\n bearerAuth: process.env[\"BEARER_AUTH\"], // defaults to the BEARER_AUTH env var\n environment: \"production\",\n});\n\nconst managedDocVersion = await client.registry.createAPIDocumentVersion(\"slug\", {\n namespace: \"namespace\",\n version: \"\",\n document: \"\",\n});\nconsole.log(managedDocVersion);" + }, + { + "label": "Shell", + "lang": "Shell", + "source": "scalarapi registry create-api-document-version 'slug' --bearer-auth \"$BEARER_AUTH\" --namespace 'namespace' --version-command 'version' --document 'document'" + }, + { + "label": "Python", + "lang": "Python", + "source": "import os\n\nfrom scalar_api import ScalarApi\n\nclient = ScalarApi(\n bearer_auth=os.environ.get(\"BEARER_AUTH\"),\n)\n\nregistry = client.registry.create_api_document_version(\n namespace=\"namespace\",\n slug=\"slug\",\n version=\"\",\n document=\"\",\n idempotency_key=\"\",\n)\nprint(registry)" + }, + { + "label": "Go", + "lang": "Go", + "source": "package main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"os\"\n\n\tsdk \"scalar-api\"\n\t\"scalar-api/option\"\n)\n\nfunc main() {\n\tclient := sdk.NewClient(\n\t\toption.WithBearerAuth(os.Getenv(\"BEARER_AUTH\")),\n\t)\n\n\tregistry, err := client.Registry.NewAPIDocumentVersion(context.Background(), \"namespace\", \"slug\", sdk.RegistryNewAPIDocumentVersionParams{\n\t\tDocument: \"\",\n\t\tVersion: \"\",\n\t})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tfmt.Println(registry)\n}" + }, + { + "label": "Kotlin", + "lang": "Kotlin", + "source": "import com.scalar.api.client.ScalarApiClient\nimport com.scalar.api.client.okhttp.ScalarApiOkHttpClient\nimport com.scalar.api.models.registry.RegistryCreateApiDocumentVersionParams\n\nval client: ScalarApiClient = ScalarApiOkHttpClient.builder()\n .bearerAuth(System.getenv(\"BEARER_AUTH\"))\n .build()\n\nval params = RegistryCreateApiDocumentVersionParams.builder()\n .namespace(\"namespace\")\n .slug(\"slug\")\n .version(\"version\")\n .document(\"document\")\n .build()\nval registry = client.registry().createApiDocumentVersion(params)\nprintln(registry)" + }, + { + "label": "Ruby", + "lang": "Ruby", + "source": "require \"json\"\nrequire \"scalar-api\"\n\nclient = ScalarApi::Client.new(\n bearer_auth: ENV[\"BEARER_AUTH\"],\n)\n\nresponse = client.registry.create_api_document_version(\"smoke-test\", { namespace: \"namespace\", version: \"version\", document: \"document\", force: \"force\", last_known_version_sha: \"last_known_version_sha\" })\nputs response.inspect" + }, + { + "label": "Java", + "lang": "Java", + "source": "import com.scalar.api.client.ScalarApiClient;\nimport com.scalar.api.client.okhttp.ScalarApiOkHttpClient;\nimport com.scalar.api.models.registry.RegistryCreateApiDocumentVersionParams;\n\nScalarApiClient client = ScalarApiOkHttpClient.builder()\n .bearerAuth(System.getenv(\"BEARER_AUTH\"))\n .build();\n\nRegistryCreateApiDocumentVersionParams params = RegistryCreateApiDocumentVersionParams.builder()\n .namespace(\"namespace\")\n .slug(\"slug\")\n .version(\"version\")\n .document(\"document\")\n .build();\nvar registry = client.registry().createApiDocumentVersion(params);\nSystem.out.println(registry);" + }, + { + "lang": "Shell", + "label": "CLI", + "source": "scalarapi registry create-api-document-version 'slug' --bearer-auth \"$BEARER_AUTH\" --namespace 'namespace' --version-command 'version' --document 'document'" + } + ] + } + }, + "/v1/apis/{namespace}/{slug}/access-group": { + "post": { + "tags": [ + "Registry" + ], + "description": "Add an access group to an API document.", + "summary": "Add access group", + "operationId": "addApiDocumentAccessGroup", + "responses": { + "200": { + "description": "Default Response", + "content": { + "application/json": { + "schema": { + "type": "null" + } + } + } + }, + "400": { + "description": "Bad request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/400" + } + } + } + }, + "401": { + "description": "No auth", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/401" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/403" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/404" + } + } + } + }, + "422": { + "description": "Invalid payload", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/422" + } + } + } + }, + "500": { + "description": "Uncaught error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/500" + } + } + } + } + }, + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/access-group" + } + } + }, + "required": true + }, + "parameters": [ + { + "schema": { + "type": "string" + }, + "in": "path", + "name": "namespace", + "required": true + }, + { + "schema": { + "type": "string" + }, + "in": "path", + "name": "slug", + "required": true + } + ], + "x-codeSamples": [ + { + "label": "TypeScript", + "lang": "TypeScript", + "source": "import ScalarAPI from \"@scalar/sdk\";\n\nconst client = new ScalarAPI({\n bearerAuth: process.env[\"BEARER_AUTH\"], // defaults to the BEARER_AUTH env var\n environment: \"production\",\n});\n\nawait client.registry.createAPIDocumentAccessGroup(\"slug\", {\n namespace: \"namespace\",\n accessGroupSlug: \"\",\n});" + }, + { + "label": "Shell", + "lang": "Shell", + "source": "scalarapi registry create-api-document-access-group 'slug' --bearer-auth \"$BEARER_AUTH\" --namespace 'namespace' --access-group-slug 'accessGroupSlug'" + }, + { + "label": "Python", + "lang": "Python", + "source": "import os\n\nfrom scalar_api import ScalarApi\n\nclient = ScalarApi(\n bearer_auth=os.environ.get(\"BEARER_AUTH\"),\n)\n\nregistry = client.registry.create_api_document_access_group(\n namespace=\"namespace\",\n slug=\"slug\",\n access_group_slug=\"\",\n idempotency_key=\"\",\n)\nprint(registry)" + }, + { + "label": "Go", + "lang": "Go", + "source": "package main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"os\"\n\n\tsdk \"scalar-api\"\n\t\"scalar-api/option\"\n)\n\nfunc main() {\n\tclient := sdk.NewClient(\n\t\toption.WithBearerAuth(os.Getenv(\"BEARER_AUTH\")),\n\t)\n\n\tregistry, err := client.Registry.NewAPIDocumentAccessGroup(context.Background(), \"namespace\", \"slug\", sdk.RegistryNewAPIDocumentAccessGroupParams{\n\t\tAccessGroup: sdk.AccessGroup{\n\t\tAccessGroupSlug: \"\",\n\t},\n\t})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tfmt.Println(registry)\n}" + }, + { + "label": "Kotlin", + "lang": "Kotlin", + "source": "import com.scalar.api.client.ScalarApiClient\nimport com.scalar.api.client.okhttp.ScalarApiOkHttpClient\nimport com.scalar.api.models.registry.RegistryCreateApiDocumentAccessGroupParams\n\nval client: ScalarApiClient = ScalarApiOkHttpClient.builder()\n .bearerAuth(System.getenv(\"BEARER_AUTH\"))\n .build()\n\nval params = RegistryCreateApiDocumentAccessGroupParams.builder()\n .namespace(\"namespace\")\n .slug(\"slug\")\n .accessGroupSlug(\"accessGroupSlug\")\n .build()\nval registry = client.registry().createApiDocumentAccessGroup(params)\nprintln(registry)" + }, + { + "label": "Ruby", + "lang": "Ruby", + "source": "require \"json\"\nrequire \"scalar-api\"\n\nclient = ScalarApi::Client.new(\n bearer_auth: ENV[\"BEARER_AUTH\"],\n)\n\nresponse = client.registry.create_api_document_access_group(\"smoke-test\", { namespace: \"namespace\", access_group_slug: \"access_group_slug\" })\nputs response.inspect" + }, + { + "label": "Java", + "lang": "Java", + "source": "import com.scalar.api.client.ScalarApiClient;\nimport com.scalar.api.client.okhttp.ScalarApiOkHttpClient;\nimport com.scalar.api.models.registry.RegistryCreateApiDocumentAccessGroupParams;\n\nScalarApiClient client = ScalarApiOkHttpClient.builder()\n .bearerAuth(System.getenv(\"BEARER_AUTH\"))\n .build();\n\nRegistryCreateApiDocumentAccessGroupParams params = RegistryCreateApiDocumentAccessGroupParams.builder()\n .namespace(\"namespace\")\n .slug(\"slug\")\n .accessGroupSlug(\"accessGroupSlug\")\n .build();\nvar registry = client.registry().createApiDocumentAccessGroup(params);\nSystem.out.println(registry);" + }, + { + "lang": "Shell", + "label": "CLI", + "source": "scalarapi registry create-api-document-access-group 'slug' --bearer-auth \"$BEARER_AUTH\" --namespace 'namespace' --access-group-slug 'accessGroupSlug'" + } + ] + }, + "delete": { + "tags": [ + "Registry" + ], + "description": "Remove an access group from an API document.", + "summary": "Remove access group", + "operationId": "removeApiDocumentAccessGroup", + "responses": { + "200": { + "description": "Default Response", + "content": { + "application/json": { + "schema": { + "type": "null" + } + } + } + }, + "400": { + "description": "Bad request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/400" + } + } + } + }, + "401": { + "description": "No auth", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/401" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/403" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/404" + } + } + } + }, + "422": { + "description": "Invalid payload", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/422" + } + } + } + }, + "500": { + "description": "Uncaught error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/500" + } + } + } + } + }, + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/access-group" + } + } + }, + "required": true + }, + "parameters": [ + { + "schema": { + "type": "string" + }, + "in": "path", + "name": "namespace", + "required": true + }, + { + "schema": { + "type": "string" + }, + "in": "path", + "name": "slug", + "required": true + } + ], + "x-codeSamples": [ + { + "label": "TypeScript", + "lang": "TypeScript", + "source": "import ScalarAPI from \"@scalar/sdk\";\n\nconst client = new ScalarAPI({\n bearerAuth: process.env[\"BEARER_AUTH\"], // defaults to the BEARER_AUTH env var\n environment: \"production\",\n});\n\nawait client.registry.deleteAPIDocumentAccessGroup(\"slug\", {\n namespace: \"namespace\",\n accessGroupSlug: \"\",\n});" + }, + { + "label": "Shell", + "lang": "Shell", + "source": "scalarapi registry delete-api-document-access-group 'slug' --bearer-auth \"$BEARER_AUTH\" --namespace 'namespace' --access-group-slug 'accessGroupSlug'" + }, + { + "label": "Python", + "lang": "Python", + "source": "import os\n\nfrom scalar_api import ScalarApi\n\nclient = ScalarApi(\n bearer_auth=os.environ.get(\"BEARER_AUTH\"),\n)\n\nregistry = client.registry.delete_api_document_access_group(\n namespace=\"namespace\",\n slug=\"slug\",\n access_group_slug=\"\",\n idempotency_key=\"\",\n)\nprint(registry)" + }, + { + "label": "Go", + "lang": "Go", + "source": "package main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"os\"\n\n\tsdk \"scalar-api\"\n\t\"scalar-api/option\"\n)\n\nfunc main() {\n\tclient := sdk.NewClient(\n\t\toption.WithBearerAuth(os.Getenv(\"BEARER_AUTH\")),\n\t)\n\n\tregistry, err := client.Registry.DeleteAPIDocumentAccessGroup(context.Background(), \"namespace\", \"slug\", sdk.RegistryDeleteAPIDocumentAccessGroupParams{\n\t\tAccessGroup: sdk.AccessGroup{\n\t\tAccessGroupSlug: \"\",\n\t},\n\t})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tfmt.Println(registry)\n}" + }, + { + "label": "Kotlin", + "lang": "Kotlin", + "source": "import com.scalar.api.client.ScalarApiClient\nimport com.scalar.api.client.okhttp.ScalarApiOkHttpClient\nimport com.scalar.api.models.registry.RegistryDeleteApiDocumentAccessGroupParams\n\nval client: ScalarApiClient = ScalarApiOkHttpClient.builder()\n .bearerAuth(System.getenv(\"BEARER_AUTH\"))\n .build()\n\nval params = RegistryDeleteApiDocumentAccessGroupParams.builder()\n .namespace(\"namespace\")\n .slug(\"slug\")\n .accessGroupSlug(\"accessGroupSlug\")\n .build()\nval registry = client.registry().deleteApiDocumentAccessGroup(params)\nprintln(registry)" + }, + { + "label": "Ruby", + "lang": "Ruby", + "source": "require \"json\"\nrequire \"scalar-api\"\n\nclient = ScalarApi::Client.new(\n bearer_auth: ENV[\"BEARER_AUTH\"],\n)\n\nresponse = client.registry.delete_api_document_access_group(\"smoke-test\", { namespace: \"namespace\", access_group_slug: \"access_group_slug\" })\nputs response.inspect" + }, + { + "label": "Java", + "lang": "Java", + "source": "import com.scalar.api.client.ScalarApiClient;\nimport com.scalar.api.client.okhttp.ScalarApiOkHttpClient;\nimport com.scalar.api.models.registry.RegistryDeleteApiDocumentAccessGroupParams;\n\nScalarApiClient client = ScalarApiOkHttpClient.builder()\n .bearerAuth(System.getenv(\"BEARER_AUTH\"))\n .build();\n\nRegistryDeleteApiDocumentAccessGroupParams params = RegistryDeleteApiDocumentAccessGroupParams.builder()\n .namespace(\"namespace\")\n .slug(\"slug\")\n .accessGroupSlug(\"accessGroupSlug\")\n .build();\nvar registry = client.registry().deleteApiDocumentAccessGroup(params);\nSystem.out.println(registry);" + }, + { + "lang": "Shell", + "label": "CLI", + "source": "scalarapi registry delete-api-document-access-group 'slug' --bearer-auth \"$BEARER_AUTH\" --namespace 'namespace' --access-group-slug 'accessGroupSlug'" + } + ] + } + }, + "/v1/schemas/{namespace}": { + "get": { + "tags": [ + "Schemas" + ], + "description": "List schemas in a namespace.", + "summary": "List all shared components", + "operationId": "listSchemas", + "responses": { + "200": { + "description": "Default Response", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/schema" + } + } + } + } + }, + "400": { + "description": "Bad request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/400" + } + } + } + }, + "401": { + "description": "No auth", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/401" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/403" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/404" + } + } + } + }, + "422": { + "description": "Invalid payload", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/422" + } + } + } + }, + "500": { + "description": "Uncaught error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/500" + } + } + } + } + }, + "parameters": [ + { + "schema": { + "type": "string" + }, + "in": "path", + "name": "namespace", + "required": true + } + ], + "x-codeSamples": [ + { + "label": "TypeScript", + "lang": "TypeScript", + "source": "import ScalarAPI from \"@scalar/sdk\";\n\nconst client = new ScalarAPI({\n bearerAuth: process.env[\"BEARER_AUTH\"], // defaults to the BEARER_AUTH env var\n environment: \"production\",\n});\n\nconst list = await client.schemas.list(\"namespace\");\nconsole.log(list);" + }, + { + "label": "Shell", + "lang": "Shell", + "source": "scalarapi schemas list 'namespace' --bearer-auth \"$BEARER_AUTH\"" + }, + { + "label": "Python", + "lang": "Python", + "source": "import os\n\nfrom scalar_api import ScalarApi\n\nclient = ScalarApi(\n bearer_auth=os.environ.get(\"BEARER_AUTH\"),\n)\n\nschema = client.schemas.list(\n namespace=\"namespace\",\n)\nprint(schema)" + }, + { + "label": "Go", + "lang": "Go", + "source": "package main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"os\"\n\n\tsdk \"scalar-api\"\n\t\"scalar-api/option\"\n)\n\nfunc main() {\n\tclient := sdk.NewClient(\n\t\toption.WithBearerAuth(os.Getenv(\"BEARER_AUTH\")),\n\t)\n\n\tschema, err := client.Schemas.List(context.Background(), \"namespace\")\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tfmt.Println(schema)\n}" + }, + { + "label": "Kotlin", + "lang": "Kotlin", + "source": "import com.scalar.api.client.ScalarApiClient\nimport com.scalar.api.client.okhttp.ScalarApiOkHttpClient\nimport com.scalar.api.models.schemas.SchemaListParams\n\nval client: ScalarApiClient = ScalarApiOkHttpClient.builder()\n .bearerAuth(System.getenv(\"BEARER_AUTH\"))\n .build()\n\nval params = SchemaListParams.builder()\n .namespace(\"namespace\")\n .build()\nval schema = client.schemas().list(params)\nprintln(schema)" + }, + { + "label": "Ruby", + "lang": "Ruby", + "source": "require \"json\"\nrequire \"scalar-api\"\n\nclient = ScalarApi::Client.new(\n bearer_auth: ENV[\"BEARER_AUTH\"],\n)\n\nresponse = client.schemas.list(\"smoke-test\")\nputs response.inspect" + }, + { + "label": "Java", + "lang": "Java", + "source": "import com.scalar.api.client.ScalarApiClient;\nimport com.scalar.api.client.okhttp.ScalarApiOkHttpClient;\nimport com.scalar.api.models.schemas.SchemaListParams;\n\nScalarApiClient client = ScalarApiOkHttpClient.builder()\n .bearerAuth(System.getenv(\"BEARER_AUTH\"))\n .build();\n\nSchemaListParams params = SchemaListParams.builder()\n .namespace(\"namespace\")\n .build();\nvar schema = client.schemas().list(params);\nSystem.out.println(schema);" + }, + { + "lang": "Shell", + "label": "CLI", + "source": "scalarapi schemas list 'namespace' --bearer-auth \"$BEARER_AUTH\"" + } + ] + }, + "post": { + "tags": [ + "Schemas" + ], + "description": "Create a schema in a namespace.", + "summary": "Create a shared component", + "operationId": "createSchema", + "responses": { + "200": { + "description": "Default Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/uid" + } + } + } + }, + "400": { + "description": "Bad request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/400" + } + } + } + }, + "401": { + "description": "No auth", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/401" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/403" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/404" + } + } + } + }, + "422": { + "description": "Invalid payload", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/422" + } + } + } + }, + "500": { + "description": "Uncaught error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/500" + } + } + } + } + }, + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "title": { + "type": "string" + }, + "description": { + "type": "string" + }, + "version": { + "$ref": "#/components/schemas/version" + }, + "slug": { + "type": "string" + }, + "isPrivate": { + "type": "boolean" + }, + "document": { + "type": "string" + } + }, + "required": [ + "title", + "version", + "slug", + "document" + ], + "additionalProperties": false + } + } + }, + "required": true + }, + "parameters": [ + { + "schema": { + "type": "string" + }, + "in": "path", + "name": "namespace", + "required": true + } + ], + "x-codeSamples": [ + { + "label": "TypeScript", + "lang": "TypeScript", + "source": "import ScalarAPI from \"@scalar/sdk\";\n\nconst client = new ScalarAPI({\n bearerAuth: process.env[\"BEARER_AUTH\"], // defaults to the BEARER_AUTH env var\n environment: \"production\",\n});\n\nconst uID = await client.schemas.create(\"namespace\", {\n title: \"\",\n version: \"\",\n slug: \"\",\n document: \"\",\n});\nconsole.log(uID);" + }, + { + "label": "Shell", + "lang": "Shell", + "source": "scalarapi schemas create 'namespace' --bearer-auth \"$BEARER_AUTH\" --title 'title' --version-command 'version' --slug 'slug' --document 'document'" + }, + { + "label": "Python", + "lang": "Python", + "source": "import os\n\nfrom scalar_api import ScalarApi\n\nclient = ScalarApi(\n bearer_auth=os.environ.get(\"BEARER_AUTH\"),\n)\n\nschema = client.schemas.create(\n namespace=\"namespace\",\n title=\"\",\n version=\"\",\n slug=\"\",\n document=\"\",\n idempotency_key=\"\",\n)\nprint(schema)" + }, + { + "label": "Go", + "lang": "Go", + "source": "package main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"os\"\n\n\tsdk \"scalar-api\"\n\t\"scalar-api/option\"\n)\n\nfunc main() {\n\tclient := sdk.NewClient(\n\t\toption.WithBearerAuth(os.Getenv(\"BEARER_AUTH\")),\n\t)\n\n\tschema, err := client.Schemas.New(context.Background(), \"namespace\", sdk.SchemaNewParams{\n\t\tDocument: \"\",\n\t\tSlug: \"\",\n\t\tTitle: \"\",\n\t\tVersion: \"\",\n\t})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tfmt.Println(schema)\n}" + }, + { + "label": "Kotlin", + "lang": "Kotlin", + "source": "import com.scalar.api.client.ScalarApiClient\nimport com.scalar.api.client.okhttp.ScalarApiOkHttpClient\nimport com.scalar.api.models.schemas.SchemaCreateParams\n\nval client: ScalarApiClient = ScalarApiOkHttpClient.builder()\n .bearerAuth(System.getenv(\"BEARER_AUTH\"))\n .build()\n\nval params = SchemaCreateParams.builder()\n .namespace(\"namespace\")\n .title(\"title\")\n .version(\"version\")\n .slug(\"slug\")\n .document(\"document\")\n .build()\nval schema = client.schemas().create(params)\nprintln(schema)" + }, + { + "label": "Ruby", + "lang": "Ruby", + "source": "require \"json\"\nrequire \"scalar-api\"\n\nclient = ScalarApi::Client.new(\n bearer_auth: ENV[\"BEARER_AUTH\"],\n)\n\nresponse = client.schemas.create(\"smoke-test\", { title: \"title\", description: \"description\", version: \"version\", slug: \"slug\", is_private: \"is_private\", document: \"document\" })\nputs response.inspect" + }, + { + "label": "Java", + "lang": "Java", + "source": "import com.scalar.api.client.ScalarApiClient;\nimport com.scalar.api.client.okhttp.ScalarApiOkHttpClient;\nimport com.scalar.api.models.schemas.SchemaCreateParams;\n\nScalarApiClient client = ScalarApiOkHttpClient.builder()\n .bearerAuth(System.getenv(\"BEARER_AUTH\"))\n .build();\n\nSchemaCreateParams params = SchemaCreateParams.builder()\n .namespace(\"namespace\")\n .title(\"title\")\n .version(\"version\")\n .slug(\"slug\")\n .document(\"document\")\n .build();\nvar schema = client.schemas().create(params);\nSystem.out.println(schema);" + }, + { + "lang": "Shell", + "label": "CLI", + "source": "scalarapi schemas create 'namespace' --bearer-auth \"$BEARER_AUTH\" --title 'title' --version-command 'version' --slug 'slug' --document 'document'" + } + ] + } + }, + "/v1/schemas/{namespace}/{slug}": { + "patch": { + "tags": [ + "Schemas" + ], + "description": "Update schema metadata.", + "summary": "Update shared component metadata", + "operationId": "updateSchema", + "responses": { + "200": { + "description": "Default Response", + "content": { + "application/json": { + "schema": { + "type": "null" + } + } + } + }, + "400": { + "description": "Bad request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/400" + } + } + } + }, + "401": { + "description": "No auth", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/401" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/403" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/404" + } + } + } + }, + "422": { + "description": "Invalid payload", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/422" + } + } + } + }, + "500": { + "description": "Uncaught error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/500" + } + } + } + } + }, + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "title": { + "type": "string" + }, + "description": { + "type": "string" + }, + "isPrivate": { + "type": "boolean" + } + }, + "additionalProperties": false + } + } + }, + "required": true + }, + "parameters": [ + { + "schema": { + "type": "string" + }, + "in": "path", + "name": "namespace", + "required": true + }, + { + "schema": { + "type": "string" + }, + "in": "path", + "name": "slug", + "required": true + } + ], + "x-codeSamples": [ + { + "label": "TypeScript", + "lang": "TypeScript", + "source": "import ScalarAPI from \"@scalar/sdk\";\n\nconst client = new ScalarAPI({\n bearerAuth: process.env[\"BEARER_AUTH\"], // defaults to the BEARER_AUTH env var\n environment: \"production\",\n});\n\nawait client.schemas.update(\"slug\", {\n namespace: \"namespace\",\n});" + }, + { + "label": "Shell", + "lang": "Shell", + "source": "scalarapi schemas update 'slug' --bearer-auth \"$BEARER_AUTH\" --namespace 'namespace'" + }, + { + "label": "Python", + "lang": "Python", + "source": "import os\n\nfrom scalar_api import ScalarApi\n\nclient = ScalarApi(\n bearer_auth=os.environ.get(\"BEARER_AUTH\"),\n)\n\nschema = client.schemas.update(\n namespace=\"namespace\",\n slug=\"slug\",\n idempotency_key=\"\",\n)\nprint(schema)" + }, + { + "label": "Go", + "lang": "Go", + "source": "package main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"os\"\n\n\tsdk \"scalar-api\"\n\t\"scalar-api/option\"\n)\n\nfunc main() {\n\tclient := sdk.NewClient(\n\t\toption.WithBearerAuth(os.Getenv(\"BEARER_AUTH\")),\n\t)\n\n\tschema, err := client.Schemas.Update(context.Background(), \"namespace\", \"slug\", sdk.SchemaUpdateParams{})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tfmt.Println(schema)\n}" + }, + { + "label": "Kotlin", + "lang": "Kotlin", + "source": "import com.scalar.api.client.ScalarApiClient\nimport com.scalar.api.client.okhttp.ScalarApiOkHttpClient\nimport com.scalar.api.models.schemas.SchemaUpdateParams\n\nval client: ScalarApiClient = ScalarApiOkHttpClient.builder()\n .bearerAuth(System.getenv(\"BEARER_AUTH\"))\n .build()\n\nval params = SchemaUpdateParams.builder()\n .namespace(\"namespace\")\n .slug(\"slug\")\n .build()\nval schema = client.schemas().update(params)\nprintln(schema)" + }, + { + "label": "Ruby", + "lang": "Ruby", + "source": "require \"json\"\nrequire \"scalar-api\"\n\nclient = ScalarApi::Client.new(\n bearer_auth: ENV[\"BEARER_AUTH\"],\n)\n\nresponse = client.schemas.update(\"smoke-test\", { namespace: \"namespace\", title: \"title\", description: \"description\", is_private: \"is_private\" })\nputs response.inspect" + }, + { + "label": "Java", + "lang": "Java", + "source": "import com.scalar.api.client.ScalarApiClient;\nimport com.scalar.api.client.okhttp.ScalarApiOkHttpClient;\nimport com.scalar.api.models.schemas.SchemaUpdateParams;\n\nScalarApiClient client = ScalarApiOkHttpClient.builder()\n .bearerAuth(System.getenv(\"BEARER_AUTH\"))\n .build();\n\nSchemaUpdateParams params = SchemaUpdateParams.builder()\n .namespace(\"namespace\")\n .slug(\"slug\")\n .build();\nvar schema = client.schemas().update(params);\nSystem.out.println(schema);" + }, + { + "lang": "Shell", + "label": "CLI", + "source": "scalarapi schemas update 'slug' --bearer-auth \"$BEARER_AUTH\" --namespace 'namespace'" + } + ] + }, + "delete": { + "tags": [ + "Schemas" + ], + "description": "Delete a schema and all related versions.", + "summary": "Delete a shared component", + "operationId": "deleteSchema", + "responses": { + "200": { + "description": "Default Response", + "content": { + "application/json": { + "schema": { + "type": "null" + } + } + } + }, + "400": { + "description": "Bad request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/400" + } + } + } + }, + "401": { + "description": "No auth", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/401" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/403" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/404" + } + } + } + }, + "422": { + "description": "Invalid payload", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/422" + } + } + } + }, + "500": { + "description": "Uncaught error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/500" + } + } + } + } + }, + "parameters": [ + { + "schema": { + "type": "string" + }, + "in": "path", + "name": "namespace", + "required": true + }, + { + "schema": { + "type": "string" + }, + "in": "path", + "name": "slug", + "required": true + } + ], + "x-codeSamples": [ + { + "label": "TypeScript", + "lang": "TypeScript", + "source": "import ScalarAPI from \"@scalar/sdk\";\n\nconst client = new ScalarAPI({\n bearerAuth: process.env[\"BEARER_AUTH\"], // defaults to the BEARER_AUTH env var\n environment: \"production\",\n});\n\nawait client.schemas.delete(\"slug\", {\n namespace: \"namespace\",\n});" + }, + { + "label": "Shell", + "lang": "Shell", + "source": "scalarapi schemas delete 'slug' --bearer-auth \"$BEARER_AUTH\" --namespace 'namespace'" + }, + { + "label": "Python", + "lang": "Python", + "source": "import os\n\nfrom scalar_api import ScalarApi\n\nclient = ScalarApi(\n bearer_auth=os.environ.get(\"BEARER_AUTH\"),\n)\n\nschema = client.schemas.delete(\n namespace=\"namespace\",\n slug=\"slug\",\n idempotency_key=\"\",\n)\nprint(schema)" + }, + { + "label": "Go", + "lang": "Go", + "source": "package main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"os\"\n\n\tsdk \"scalar-api\"\n\t\"scalar-api/option\"\n)\n\nfunc main() {\n\tclient := sdk.NewClient(\n\t\toption.WithBearerAuth(os.Getenv(\"BEARER_AUTH\")),\n\t)\n\n\tschema, err := client.Schemas.Delete(context.Background(), \"namespace\", \"slug\")\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tfmt.Println(schema)\n}" + }, + { + "label": "Kotlin", + "lang": "Kotlin", + "source": "import com.scalar.api.client.ScalarApiClient\nimport com.scalar.api.client.okhttp.ScalarApiOkHttpClient\nimport com.scalar.api.models.schemas.SchemaDeleteParams\n\nval client: ScalarApiClient = ScalarApiOkHttpClient.builder()\n .bearerAuth(System.getenv(\"BEARER_AUTH\"))\n .build()\n\nval params = SchemaDeleteParams.builder()\n .namespace(\"namespace\")\n .slug(\"slug\")\n .build()\nval schema = client.schemas().delete(params)\nprintln(schema)" + }, + { + "label": "Ruby", + "lang": "Ruby", + "source": "require \"json\"\nrequire \"scalar-api\"\n\nclient = ScalarApi::Client.new(\n bearer_auth: ENV[\"BEARER_AUTH\"],\n)\n\nresponse = client.schemas.delete(\"smoke-test\", { namespace: \"namespace\" })\nputs response.inspect" + }, + { + "label": "Java", + "lang": "Java", + "source": "import com.scalar.api.client.ScalarApiClient;\nimport com.scalar.api.client.okhttp.ScalarApiOkHttpClient;\nimport com.scalar.api.models.schemas.SchemaDeleteParams;\n\nScalarApiClient client = ScalarApiOkHttpClient.builder()\n .bearerAuth(System.getenv(\"BEARER_AUTH\"))\n .build();\n\nSchemaDeleteParams params = SchemaDeleteParams.builder()\n .namespace(\"namespace\")\n .slug(\"slug\")\n .build();\nvar schema = client.schemas().delete(params);\nSystem.out.println(schema);" + }, + { + "lang": "Shell", + "label": "CLI", + "source": "scalarapi schemas delete 'slug' --bearer-auth \"$BEARER_AUTH\" --namespace 'namespace'" + } + ] + } + }, + "/v1/schemas/{namespace}/{slug}/version/{semver}": { + "get": { + "tags": [ + "Schemas" + ], + "description": "Get a specific schema version document.", + "summary": "Get a shared component document", + "operationId": "getSchemaVersion", + "responses": { + "200": { + "description": "Default Response", + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + } + }, + "400": { + "description": "Bad request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/400" + } + } + } + }, + "401": { + "description": "No auth", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/401" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/403" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/404" + } + } + } + }, + "422": { + "description": "Invalid payload", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/422" + } + } + } + }, + "500": { + "description": "Uncaught error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/500" + } + } + } + } + }, + "parameters": [ + { + "schema": { + "type": "string" + }, + "in": "path", + "name": "namespace", + "required": true + }, + { + "schema": { + "type": "string" + }, + "in": "path", + "name": "slug", + "required": true + }, + { + "schema": { + "type": "string" + }, + "in": "path", + "name": "semver", + "required": true + } + ], + "x-codeSamples": [ + { + "label": "TypeScript", + "lang": "TypeScript", + "source": "import ScalarAPI from \"@scalar/sdk\";\n\nconst client = new ScalarAPI({\n bearerAuth: process.env[\"BEARER_AUTH\"], // defaults to the BEARER_AUTH env var\n environment: \"production\",\n});\n\nconst string_ = await client.schemas.version.retrieveSchema(\"semver\", {\n namespace: \"namespace\",\n slug: \"slug\",\n});\nconsole.log(string_);" + }, + { + "label": "Shell", + "lang": "Shell", + "source": "scalarapi schemas:version-command retrieve-schema 'semver' --bearer-auth \"$BEARER_AUTH\" --namespace 'namespace' --slug 'slug'" + }, + { + "label": "Python", + "lang": "Python", + "source": "import os\n\nfrom scalar_api import ScalarApi\n\nclient = ScalarApi(\n bearer_auth=os.environ.get(\"BEARER_AUTH\"),\n)\n\nversion = client.schemas.version.retrieve_schema(\n namespace=\"namespace\",\n slug=\"slug\",\n semver=\"semver\",\n)\nprint(version)" + }, + { + "label": "Go", + "lang": "Go", + "source": "package main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"os\"\n\n\tsdk \"scalar-api\"\n\t\"scalar-api/option\"\n)\n\nfunc main() {\n\tclient := sdk.NewClient(\n\t\toption.WithBearerAuth(os.Getenv(\"BEARER_AUTH\")),\n\t)\n\n\tversion, err := client.Schemas.Version.GetSchema(context.Background(), \"namespace\", \"slug\", \"semver\")\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tfmt.Println(version)\n}" + }, + { + "label": "Kotlin", + "lang": "Kotlin", + "source": "import com.scalar.api.client.ScalarApiClient\nimport com.scalar.api.client.okhttp.ScalarApiOkHttpClient\nimport com.scalar.api.models.schemas.version.VersionRetrieveSchemaParams\n\nval client: ScalarApiClient = ScalarApiOkHttpClient.builder()\n .bearerAuth(System.getenv(\"BEARER_AUTH\"))\n .build()\n\nval params = VersionRetrieveSchemaParams.builder()\n .namespace(\"namespace\")\n .slug(\"slug\")\n .semver(\"semver\")\n .build()\nval version = client.schemas().version().retrieveSchema(params)\nprintln(version)" + }, + { + "label": "Ruby", + "lang": "Ruby", + "source": "require \"json\"\nrequire \"scalar-api\"\n\nclient = ScalarApi::Client.new(\n bearer_auth: ENV[\"BEARER_AUTH\"],\n)\n\nresponse = client.schemas.version.retrieve_schema(\"smoke-test\", { namespace: \"namespace\", slug: \"slug\" })\nputs response.inspect" + }, + { + "label": "Java", + "lang": "Java", + "source": "import com.scalar.api.client.ScalarApiClient;\nimport com.scalar.api.client.okhttp.ScalarApiOkHttpClient;\nimport com.scalar.api.models.schemas.version.VersionRetrieveSchemaParams;\n\nScalarApiClient client = ScalarApiOkHttpClient.builder()\n .bearerAuth(System.getenv(\"BEARER_AUTH\"))\n .build();\n\nVersionRetrieveSchemaParams params = VersionRetrieveSchemaParams.builder()\n .namespace(\"namespace\")\n .slug(\"slug\")\n .semver(\"semver\")\n .build();\nvar version = client.schemas().version().retrieveSchema(params);\nSystem.out.println(version);" + }, + { + "lang": "Shell", + "label": "CLI", + "source": "scalarapi schemas:version-command retrieve-schema 'semver' --bearer-auth \"$BEARER_AUTH\" --namespace 'namespace' --slug 'slug'" + } + ] + }, + "delete": { + "tags": [ + "Schemas" + ], + "description": "Delete a schema version.", + "summary": "Delete a shared component version", + "operationId": "deleteSchemaVersion", + "responses": { + "200": { + "description": "Default Response", + "content": { + "application/json": { + "schema": { + "type": "null" + } + } + } + }, + "400": { + "description": "Bad request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/400" + } + } + } + }, + "401": { + "description": "No auth", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/401" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/403" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/404" + } + } + } + }, + "422": { + "description": "Invalid payload", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/422" + } + } + } + }, + "500": { + "description": "Uncaught error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/500" + } + } + } + } + }, + "parameters": [ + { + "schema": { + "type": "string" + }, + "in": "path", + "name": "namespace", + "required": true + }, + { + "schema": { + "type": "string" + }, + "in": "path", + "name": "slug", + "required": true + }, + { + "schema": { + "type": "string" + }, + "in": "path", + "name": "semver", + "required": true + } + ], + "x-codeSamples": [ + { + "label": "TypeScript", + "lang": "TypeScript", + "source": "import ScalarAPI from \"@scalar/sdk\";\n\nconst client = new ScalarAPI({\n bearerAuth: process.env[\"BEARER_AUTH\"], // defaults to the BEARER_AUTH env var\n environment: \"production\",\n});\n\nawait client.schemas.version.deleteSchema(\"semver\", {\n namespace: \"namespace\",\n slug: \"slug\",\n});" + }, + { + "label": "Shell", + "lang": "Shell", + "source": "scalarapi schemas:version-command delete-schema 'semver' --bearer-auth \"$BEARER_AUTH\" --namespace 'namespace' --slug 'slug'" + }, + { + "label": "Python", + "lang": "Python", + "source": "import os\n\nfrom scalar_api import ScalarApi\n\nclient = ScalarApi(\n bearer_auth=os.environ.get(\"BEARER_AUTH\"),\n)\n\nversion = client.schemas.version.delete_schema(\n namespace=\"namespace\",\n slug=\"slug\",\n semver=\"semver\",\n idempotency_key=\"\",\n)\nprint(version)" + }, + { + "label": "Go", + "lang": "Go", + "source": "package main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"os\"\n\n\tsdk \"scalar-api\"\n\t\"scalar-api/option\"\n)\n\nfunc main() {\n\tclient := sdk.NewClient(\n\t\toption.WithBearerAuth(os.Getenv(\"BEARER_AUTH\")),\n\t)\n\n\tversion, err := client.Schemas.Version.DeleteSchema(context.Background(), \"namespace\", \"slug\", \"semver\")\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tfmt.Println(version)\n}" + }, + { + "label": "Kotlin", + "lang": "Kotlin", + "source": "import com.scalar.api.client.ScalarApiClient\nimport com.scalar.api.client.okhttp.ScalarApiOkHttpClient\nimport com.scalar.api.models.schemas.version.VersionDeleteSchemaParams\n\nval client: ScalarApiClient = ScalarApiOkHttpClient.builder()\n .bearerAuth(System.getenv(\"BEARER_AUTH\"))\n .build()\n\nval params = VersionDeleteSchemaParams.builder()\n .namespace(\"namespace\")\n .slug(\"slug\")\n .semver(\"semver\")\n .build()\nval version = client.schemas().version().deleteSchema(params)\nprintln(version)" + }, + { + "label": "Ruby", + "lang": "Ruby", + "source": "require \"json\"\nrequire \"scalar-api\"\n\nclient = ScalarApi::Client.new(\n bearer_auth: ENV[\"BEARER_AUTH\"],\n)\n\nresponse = client.schemas.version.delete_schema(\"smoke-test\", { namespace: \"namespace\", slug: \"slug\" })\nputs response.inspect" + }, + { + "label": "Java", + "lang": "Java", + "source": "import com.scalar.api.client.ScalarApiClient;\nimport com.scalar.api.client.okhttp.ScalarApiOkHttpClient;\nimport com.scalar.api.models.schemas.version.VersionDeleteSchemaParams;\n\nScalarApiClient client = ScalarApiOkHttpClient.builder()\n .bearerAuth(System.getenv(\"BEARER_AUTH\"))\n .build();\n\nVersionDeleteSchemaParams params = VersionDeleteSchemaParams.builder()\n .namespace(\"namespace\")\n .slug(\"slug\")\n .semver(\"semver\")\n .build();\nvar version = client.schemas().version().deleteSchema(params);\nSystem.out.println(version);" + }, + { + "lang": "Shell", + "label": "CLI", + "source": "scalarapi schemas:version-command delete-schema 'semver' --bearer-auth \"$BEARER_AUTH\" --namespace 'namespace' --slug 'slug'" + } + ] + } + }, + "/v1/schemas/{namespace}/{slug}/version": { + "post": { + "tags": [ + "Schemas" + ], + "description": "Create a schema version.", + "summary": "Create a shared component version", + "operationId": "createSchemaVersion", + "responses": { + "200": { + "description": "Default Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/uid" + } + } + } + }, + "400": { + "description": "Bad request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/400" + } + } + } + }, + "401": { + "description": "No auth", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/401" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/403" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/404" + } + } + } + }, + "422": { + "description": "Invalid payload", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/422" + } + } + } + }, + "500": { + "description": "Uncaught error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/500" + } + } + } + } + }, + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "version": { + "$ref": "#/components/schemas/version" + }, + "document": { + "type": "string" + } + }, + "required": [ + "version", + "document" + ], + "additionalProperties": false + } + } + }, + "required": true + }, + "parameters": [ + { + "schema": { + "type": "string" + }, + "in": "path", + "name": "namespace", + "required": true + }, + { + "schema": { + "type": "string" + }, + "in": "path", + "name": "slug", + "required": true + } + ], + "x-codeSamples": [ + { + "label": "TypeScript", + "lang": "TypeScript", + "source": "import ScalarAPI from \"@scalar/sdk\";\n\nconst client = new ScalarAPI({\n bearerAuth: process.env[\"BEARER_AUTH\"], // defaults to the BEARER_AUTH env var\n environment: \"production\",\n});\n\nconst uID = await client.schemas.version.createSchema(\"slug\", {\n namespace: \"namespace\",\n version: \"\",\n document: \"\",\n});\nconsole.log(uID);" + }, + { + "label": "Shell", + "lang": "Shell", + "source": "scalarapi schemas:version-command create-schema 'slug' --bearer-auth \"$BEARER_AUTH\" --namespace 'namespace' --version-command 'version' --document 'document'" + }, + { + "label": "Python", + "lang": "Python", + "source": "import os\n\nfrom scalar_api import ScalarApi\n\nclient = ScalarApi(\n bearer_auth=os.environ.get(\"BEARER_AUTH\"),\n)\n\nversion = client.schemas.version.create_schema(\n namespace=\"namespace\",\n slug=\"slug\",\n version=\"\",\n document=\"\",\n idempotency_key=\"\",\n)\nprint(version)" + }, + { + "label": "Go", + "lang": "Go", + "source": "package main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"os\"\n\n\tsdk \"scalar-api\"\n\t\"scalar-api/option\"\n)\n\nfunc main() {\n\tclient := sdk.NewClient(\n\t\toption.WithBearerAuth(os.Getenv(\"BEARER_AUTH\")),\n\t)\n\n\tversion, err := client.Schemas.Version.NewSchema(context.Background(), \"namespace\", \"slug\", sdk.SchemaVersionNewSchemaParams{\n\t\tDocument: \"\",\n\t\tVersion: \"\",\n\t})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tfmt.Println(version)\n}" + }, + { + "label": "Kotlin", + "lang": "Kotlin", + "source": "import com.scalar.api.client.ScalarApiClient\nimport com.scalar.api.client.okhttp.ScalarApiOkHttpClient\nimport com.scalar.api.models.schemas.version.VersionCreateSchemaParams\n\nval client: ScalarApiClient = ScalarApiOkHttpClient.builder()\n .bearerAuth(System.getenv(\"BEARER_AUTH\"))\n .build()\n\nval params = VersionCreateSchemaParams.builder()\n .namespace(\"namespace\")\n .slug(\"slug\")\n .version(\"version\")\n .document(\"document\")\n .build()\nval version = client.schemas().version().createSchema(params)\nprintln(version)" + }, + { + "label": "Ruby", + "lang": "Ruby", + "source": "require \"json\"\nrequire \"scalar-api\"\n\nclient = ScalarApi::Client.new(\n bearer_auth: ENV[\"BEARER_AUTH\"],\n)\n\nresponse = client.schemas.version.create_schema(\"smoke-test\", { namespace: \"namespace\", version: \"version\", document: \"document\" })\nputs response.inspect" + }, + { + "label": "Java", + "lang": "Java", + "source": "import com.scalar.api.client.ScalarApiClient;\nimport com.scalar.api.client.okhttp.ScalarApiOkHttpClient;\nimport com.scalar.api.models.schemas.version.VersionCreateSchemaParams;\n\nScalarApiClient client = ScalarApiOkHttpClient.builder()\n .bearerAuth(System.getenv(\"BEARER_AUTH\"))\n .build();\n\nVersionCreateSchemaParams params = VersionCreateSchemaParams.builder()\n .namespace(\"namespace\")\n .slug(\"slug\")\n .version(\"version\")\n .document(\"document\")\n .build();\nvar version = client.schemas().version().createSchema(params);\nSystem.out.println(version);" + }, + { + "lang": "Shell", + "label": "CLI", + "source": "scalarapi schemas:version-command create-schema 'slug' --bearer-auth \"$BEARER_AUTH\" --namespace 'namespace' --version-command 'version' --document 'document'" + } + ] + } + }, + "/v1/schemas/{namespace}/{slug}/access-group": { + "post": { + "tags": [ + "Schemas" + ], + "description": "Add an access group to a schema.", + "summary": "Add shared component access group", + "operationId": "addSchemaAccessGroup", + "responses": { + "200": { + "description": "Default Response", + "content": { + "application/json": { + "schema": { + "type": "null" + } + } + } + }, + "400": { + "description": "Bad request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/400" + } + } + } + }, + "401": { + "description": "No auth", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/401" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/403" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/404" + } + } + } + }, + "422": { + "description": "Invalid payload", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/422" + } + } + } + }, + "500": { + "description": "Uncaught error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/500" + } + } + } + } + }, + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/access-group" + } + } + }, + "required": true + }, + "parameters": [ + { + "schema": { + "type": "string" + }, + "in": "path", + "name": "namespace", + "required": true + }, + { + "schema": { + "type": "string" + }, + "in": "path", + "name": "slug", + "required": true + } + ], + "x-codeSamples": [ + { + "label": "TypeScript", + "lang": "TypeScript", + "source": "import ScalarAPI from \"@scalar/sdk\";\n\nconst client = new ScalarAPI({\n bearerAuth: process.env[\"BEARER_AUTH\"], // defaults to the BEARER_AUTH env var\n environment: \"production\",\n});\n\nawait client.schemas.accessGroup.createSchema(\"slug\", {\n namespace: \"namespace\",\n accessGroupSlug: \"\",\n});" + }, + { + "label": "Shell", + "lang": "Shell", + "source": "scalarapi schemas:access-group create-schema 'slug' --bearer-auth \"$BEARER_AUTH\" --namespace 'namespace' --access-group-slug 'accessGroupSlug'" + }, + { + "label": "Python", + "lang": "Python", + "source": "import os\n\nfrom scalar_api import ScalarApi\n\nclient = ScalarApi(\n bearer_auth=os.environ.get(\"BEARER_AUTH\"),\n)\n\naccess_group = client.schemas.access_group.create_schema(\n namespace=\"namespace\",\n slug=\"slug\",\n access_group_slug=\"\",\n idempotency_key=\"\",\n)\nprint(access_group)" + }, + { + "label": "Go", + "lang": "Go", + "source": "package main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"os\"\n\n\tsdk \"scalar-api\"\n\t\"scalar-api/option\"\n)\n\nfunc main() {\n\tclient := sdk.NewClient(\n\t\toption.WithBearerAuth(os.Getenv(\"BEARER_AUTH\")),\n\t)\n\n\taccessGroup, err := client.Schemas.AccessGroup.NewSchema(context.Background(), \"namespace\", \"slug\", sdk.SchemaAccessGroupNewSchemaParams{\n\t\tAccessGroup: sdk.AccessGroup{\n\t\tAccessGroupSlug: \"\",\n\t},\n\t})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tfmt.Println(accessGroup)\n}" + }, + { + "label": "Kotlin", + "lang": "Kotlin", + "source": "import com.scalar.api.client.ScalarApiClient\nimport com.scalar.api.client.okhttp.ScalarApiOkHttpClient\nimport com.scalar.api.models.schemas.accessgroup.AccessGroupCreateSchemaParams\n\nval client: ScalarApiClient = ScalarApiOkHttpClient.builder()\n .bearerAuth(System.getenv(\"BEARER_AUTH\"))\n .build()\n\nval params = AccessGroupCreateSchemaParams.builder()\n .namespace(\"namespace\")\n .slug(\"slug\")\n .accessGroupSlug(\"accessGroupSlug\")\n .build()\nval accessGroup = client.schemas().accessGroup().createSchema(params)\nprintln(accessGroup)" + }, + { + "label": "Ruby", + "lang": "Ruby", + "source": "require \"json\"\nrequire \"scalar-api\"\n\nclient = ScalarApi::Client.new(\n bearer_auth: ENV[\"BEARER_AUTH\"],\n)\n\nresponse = client.schemas.accessGroup.create_schema(\"smoke-test\", { namespace: \"namespace\", access_group_slug: \"access_group_slug\" })\nputs response.inspect" + }, + { + "label": "Java", + "lang": "Java", + "source": "import com.scalar.api.client.ScalarApiClient;\nimport com.scalar.api.client.okhttp.ScalarApiOkHttpClient;\nimport com.scalar.api.models.schemas.accessgroup.AccessGroupCreateSchemaParams;\n\nScalarApiClient client = ScalarApiOkHttpClient.builder()\n .bearerAuth(System.getenv(\"BEARER_AUTH\"))\n .build();\n\nAccessGroupCreateSchemaParams params = AccessGroupCreateSchemaParams.builder()\n .namespace(\"namespace\")\n .slug(\"slug\")\n .accessGroupSlug(\"accessGroupSlug\")\n .build();\nvar accessGroup = client.schemas().accessGroup().createSchema(params);\nSystem.out.println(accessGroup);" + }, + { + "lang": "Shell", + "label": "CLI", + "source": "scalarapi schemas:access-group create-schema 'slug' --bearer-auth \"$BEARER_AUTH\" --namespace 'namespace' --access-group-slug 'accessGroupSlug'" + } + ] + }, + "delete": { + "tags": [ + "Schemas" + ], + "description": "Remove an access group from a schema.", + "summary": "Remove shared component access group", + "operationId": "removeSchemaAccessGroup", + "responses": { + "200": { + "description": "Default Response", + "content": { + "application/json": { + "schema": { + "type": "null" + } + } + } + }, + "400": { + "description": "Bad request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/400" + } + } + } + }, + "401": { + "description": "No auth", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/401" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/403" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/404" + } + } + } + }, + "422": { + "description": "Invalid payload", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/422" + } + } + } + }, + "500": { + "description": "Uncaught error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/500" + } + } + } + } + }, + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/access-group" + } + } + }, + "required": true + }, + "parameters": [ + { + "schema": { + "type": "string" + }, + "in": "path", + "name": "namespace", + "required": true + }, + { + "schema": { + "type": "string" + }, + "in": "path", + "name": "slug", + "required": true + } + ], + "x-codeSamples": [ + { + "label": "TypeScript", + "lang": "TypeScript", + "source": "import ScalarAPI from \"@scalar/sdk\";\n\nconst client = new ScalarAPI({\n bearerAuth: process.env[\"BEARER_AUTH\"], // defaults to the BEARER_AUTH env var\n environment: \"production\",\n});\n\nawait client.schemas.accessGroup.deleteSchema(\"slug\", {\n namespace: \"namespace\",\n accessGroupSlug: \"\",\n});" + }, + { + "label": "Shell", + "lang": "Shell", + "source": "scalarapi schemas:access-group delete-schema 'slug' --bearer-auth \"$BEARER_AUTH\" --namespace 'namespace' --access-group-slug 'accessGroupSlug'" + }, + { + "label": "Python", + "lang": "Python", + "source": "import os\n\nfrom scalar_api import ScalarApi\n\nclient = ScalarApi(\n bearer_auth=os.environ.get(\"BEARER_AUTH\"),\n)\n\naccess_group = client.schemas.access_group.delete_schema(\n namespace=\"namespace\",\n slug=\"slug\",\n access_group_slug=\"\",\n idempotency_key=\"\",\n)\nprint(access_group)" + }, + { + "label": "Go", + "lang": "Go", + "source": "package main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"os\"\n\n\tsdk \"scalar-api\"\n\t\"scalar-api/option\"\n)\n\nfunc main() {\n\tclient := sdk.NewClient(\n\t\toption.WithBearerAuth(os.Getenv(\"BEARER_AUTH\")),\n\t)\n\n\taccessGroup, err := client.Schemas.AccessGroup.DeleteSchema(context.Background(), \"namespace\", \"slug\", sdk.SchemaAccessGroupDeleteSchemaParams{\n\t\tAccessGroup: sdk.AccessGroup{\n\t\tAccessGroupSlug: \"\",\n\t},\n\t})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tfmt.Println(accessGroup)\n}" + }, + { + "label": "Kotlin", + "lang": "Kotlin", + "source": "import com.scalar.api.client.ScalarApiClient\nimport com.scalar.api.client.okhttp.ScalarApiOkHttpClient\nimport com.scalar.api.models.schemas.accessgroup.AccessGroupDeleteSchemaParams\n\nval client: ScalarApiClient = ScalarApiOkHttpClient.builder()\n .bearerAuth(System.getenv(\"BEARER_AUTH\"))\n .build()\n\nval params = AccessGroupDeleteSchemaParams.builder()\n .namespace(\"namespace\")\n .slug(\"slug\")\n .accessGroupSlug(\"accessGroupSlug\")\n .build()\nval accessGroup = client.schemas().accessGroup().deleteSchema(params)\nprintln(accessGroup)" + }, + { + "label": "Ruby", + "lang": "Ruby", + "source": "require \"json\"\nrequire \"scalar-api\"\n\nclient = ScalarApi::Client.new(\n bearer_auth: ENV[\"BEARER_AUTH\"],\n)\n\nresponse = client.schemas.accessGroup.delete_schema(\"smoke-test\", { namespace: \"namespace\", access_group_slug: \"access_group_slug\" })\nputs response.inspect" + }, + { + "label": "Java", + "lang": "Java", + "source": "import com.scalar.api.client.ScalarApiClient;\nimport com.scalar.api.client.okhttp.ScalarApiOkHttpClient;\nimport com.scalar.api.models.schemas.accessgroup.AccessGroupDeleteSchemaParams;\n\nScalarApiClient client = ScalarApiOkHttpClient.builder()\n .bearerAuth(System.getenv(\"BEARER_AUTH\"))\n .build();\n\nAccessGroupDeleteSchemaParams params = AccessGroupDeleteSchemaParams.builder()\n .namespace(\"namespace\")\n .slug(\"slug\")\n .accessGroupSlug(\"accessGroupSlug\")\n .build();\nvar accessGroup = client.schemas().accessGroup().deleteSchema(params);\nSystem.out.println(accessGroup);" + }, + { + "lang": "Shell", + "label": "CLI", + "source": "scalarapi schemas:access-group delete-schema 'slug' --bearer-auth \"$BEARER_AUTH\" --namespace 'namespace' --access-group-slug 'accessGroupSlug'" + } + ] + } + }, + "/v1/login-portals/{slug}": { + "get": { + "tags": [ + "Login Portals" + ], + "description": "Get a login portal by slug.", + "summary": "Get a login portal", + "operationId": "getLoginPortal", + "responses": { + "200": { + "description": "Default Response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "uid": { + "type": "string" + }, + "title": { + "type": "string" + }, + "slug": { + "type": "string" + }, + "email": { + "$ref": "#/components/schemas/login-portal-email" + }, + "page": { + "$ref": "#/components/schemas/login-portal-page" + } + }, + "required": [ + "uid", + "title", + "slug", + "email", + "page" + ], + "additionalProperties": false + } + } + } + }, + "400": { + "description": "Bad request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/400" + } + } + } + }, + "401": { + "description": "No auth", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/401" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/403" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/404" + } + } + } + }, + "422": { + "description": "Invalid payload", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/422" + } + } + } + }, + "500": { + "description": "Uncaught error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/500" + } + } + } + } + }, + "parameters": [ + { + "schema": { + "type": "string" + }, + "in": "path", + "name": "slug", + "required": true + } + ], + "x-codeSamples": [ + { + "label": "TypeScript", + "lang": "TypeScript", + "source": "import ScalarAPI from \"@scalar/sdk\";\n\nconst client = new ScalarAPI({\n bearerAuth: process.env[\"BEARER_AUTH\"], // defaults to the BEARER_AUTH env var\n environment: \"production\",\n});\n\nconst retrieve = await client.loginPortals.retrieve(\"slug\");\nconsole.log(retrieve);" + }, + { + "label": "Shell", + "lang": "Shell", + "source": "scalarapi login-portals retrieve 'slug' --bearer-auth \"$BEARER_AUTH\"" + }, + { + "label": "Python", + "lang": "Python", + "source": "import os\n\nfrom scalar_api import ScalarApi\n\nclient = ScalarApi(\n bearer_auth=os.environ.get(\"BEARER_AUTH\"),\n)\n\nlogin_portal = client.login_portals.retrieve(\n slug=\"slug\",\n)\nprint(login_portal)" + }, + { + "label": "Go", + "lang": "Go", + "source": "package main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"os\"\n\n\tsdk \"scalar-api\"\n\t\"scalar-api/option\"\n)\n\nfunc main() {\n\tclient := sdk.NewClient(\n\t\toption.WithBearerAuth(os.Getenv(\"BEARER_AUTH\")),\n\t)\n\n\tloginPortal, err := client.LoginPortals.Get(context.Background(), \"slug\")\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tfmt.Println(loginPortal)\n}" + }, + { + "label": "Kotlin", + "lang": "Kotlin", + "source": "import com.scalar.api.client.ScalarApiClient\nimport com.scalar.api.client.okhttp.ScalarApiOkHttpClient\nimport com.scalar.api.models.loginportals.LoginPortalRetrieveParams\n\nval client: ScalarApiClient = ScalarApiOkHttpClient.builder()\n .bearerAuth(System.getenv(\"BEARER_AUTH\"))\n .build()\n\nval params = LoginPortalRetrieveParams.builder()\n .slug(\"slug\")\n .build()\nval loginPortal = client.loginPortals().retrieve(params)\nprintln(loginPortal)" + }, + { + "label": "Ruby", + "lang": "Ruby", + "source": "require \"json\"\nrequire \"scalar-api\"\n\nclient = ScalarApi::Client.new(\n bearer_auth: ENV[\"BEARER_AUTH\"],\n)\n\nresponse = client.loginPortals.retrieve(\"smoke-test\")\nputs response.inspect" + }, + { + "label": "Java", + "lang": "Java", + "source": "import com.scalar.api.client.ScalarApiClient;\nimport com.scalar.api.client.okhttp.ScalarApiOkHttpClient;\nimport com.scalar.api.models.loginportals.LoginPortalRetrieveParams;\n\nScalarApiClient client = ScalarApiOkHttpClient.builder()\n .bearerAuth(System.getenv(\"BEARER_AUTH\"))\n .build();\n\nLoginPortalRetrieveParams params = LoginPortalRetrieveParams.builder()\n .slug(\"slug\")\n .build();\nvar loginPortal = client.loginPortals().retrieve(params);\nSystem.out.println(loginPortal);" + }, + { + "lang": "Shell", + "label": "CLI", + "source": "scalarapi login-portals retrieve 'slug' --bearer-auth \"$BEARER_AUTH\"" + } + ] + }, + "patch": { + "tags": [ + "Login Portals" + ], + "description": "Update metadata for a login portal.", + "summary": "Update portal metadata", + "operationId": "updateLoginPortal", + "responses": { + "200": { + "description": "Default Response", + "content": { + "application/json": { + "schema": { + "type": "null" + } + } + } + }, + "400": { + "description": "Bad request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/400" + } + } + } + }, + "401": { + "description": "No auth", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/401" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/403" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/404" + } + } + } + }, + "422": { + "description": "Invalid payload", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/422" + } + } + } + }, + "500": { + "description": "Uncaught error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/500" + } + } + } + } + }, + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "title": { + "type": "string" + } + }, + "additionalProperties": false + } + } + }, + "required": true + }, + "parameters": [ + { + "schema": { + "type": "string" + }, + "in": "path", + "name": "slug", + "required": true + } + ], + "x-codeSamples": [ + { + "label": "TypeScript", + "lang": "TypeScript", + "source": "import ScalarAPI from \"@scalar/sdk\";\n\nconst client = new ScalarAPI({\n bearerAuth: process.env[\"BEARER_AUTH\"], // defaults to the BEARER_AUTH env var\n environment: \"production\",\n});\n\nawait client.loginPortals.update(\"slug\", {});" + }, + { + "label": "Shell", + "lang": "Shell", + "source": "scalarapi login-portals update 'slug' --bearer-auth \"$BEARER_AUTH\"" + }, + { + "label": "Python", + "lang": "Python", + "source": "import os\n\nfrom scalar_api import ScalarApi\n\nclient = ScalarApi(\n bearer_auth=os.environ.get(\"BEARER_AUTH\"),\n)\n\nlogin_portal = client.login_portals.update(\n slug=\"slug\",\n idempotency_key=\"\",\n)\nprint(login_portal)" + }, + { + "label": "Go", + "lang": "Go", + "source": "package main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"os\"\n\n\tsdk \"scalar-api\"\n\t\"scalar-api/option\"\n)\n\nfunc main() {\n\tclient := sdk.NewClient(\n\t\toption.WithBearerAuth(os.Getenv(\"BEARER_AUTH\")),\n\t)\n\n\tloginPortal, err := client.LoginPortals.Update(context.Background(), \"slug\", sdk.LoginPortalUpdateParams{})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tfmt.Println(loginPortal)\n}" + }, + { + "label": "Kotlin", + "lang": "Kotlin", + "source": "import com.scalar.api.client.ScalarApiClient\nimport com.scalar.api.client.okhttp.ScalarApiOkHttpClient\nimport com.scalar.api.models.loginportals.LoginPortalUpdateParams\n\nval client: ScalarApiClient = ScalarApiOkHttpClient.builder()\n .bearerAuth(System.getenv(\"BEARER_AUTH\"))\n .build()\n\nval params = LoginPortalUpdateParams.builder()\n .slug(\"slug\")\n .build()\nval loginPortal = client.loginPortals().update(params)\nprintln(loginPortal)" + }, + { + "label": "Ruby", + "lang": "Ruby", + "source": "require \"json\"\nrequire \"scalar-api\"\n\nclient = ScalarApi::Client.new(\n bearer_auth: ENV[\"BEARER_AUTH\"],\n)\n\nresponse = client.loginPortals.update(\"smoke-test\", { title: \"title\" })\nputs response.inspect" + }, + { + "label": "Java", + "lang": "Java", + "source": "import com.scalar.api.client.ScalarApiClient;\nimport com.scalar.api.client.okhttp.ScalarApiOkHttpClient;\nimport com.scalar.api.models.loginportals.LoginPortalUpdateParams;\n\nScalarApiClient client = ScalarApiOkHttpClient.builder()\n .bearerAuth(System.getenv(\"BEARER_AUTH\"))\n .build();\n\nLoginPortalUpdateParams params = LoginPortalUpdateParams.builder()\n .slug(\"slug\")\n .build();\nvar loginPortal = client.loginPortals().update(params);\nSystem.out.println(loginPortal);" + }, + { + "lang": "Shell", + "label": "CLI", + "source": "scalarapi login-portals update 'slug' --bearer-auth \"$BEARER_AUTH\"" + } + ] + }, + "delete": { + "tags": [ + "Login Portals" + ], + "description": "Delete a login portal.", + "summary": "Delete a login portal", + "operationId": "deleteLoginPortal", + "responses": { + "200": { + "description": "Default Response", + "content": { + "application/json": { + "schema": { + "type": "null" + } + } + } + }, + "400": { + "description": "Bad request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/400" + } + } + } + }, + "401": { + "description": "No auth", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/401" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/403" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/404" + } + } + } + }, + "422": { + "description": "Invalid payload", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/422" + } + } + } + }, + "500": { + "description": "Uncaught error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/500" + } + } + } + } + }, + "parameters": [ + { + "schema": { + "type": "string" + }, + "in": "path", + "name": "slug", + "required": true + } + ], + "x-codeSamples": [ + { + "label": "TypeScript", + "lang": "TypeScript", + "source": "import ScalarAPI from \"@scalar/sdk\";\n\nconst client = new ScalarAPI({\n bearerAuth: process.env[\"BEARER_AUTH\"], // defaults to the BEARER_AUTH env var\n environment: \"production\",\n});\n\nawait client.loginPortals.delete(\"slug\");" + }, + { + "label": "Shell", + "lang": "Shell", + "source": "scalarapi login-portals delete 'slug' --bearer-auth \"$BEARER_AUTH\"" + }, + { + "label": "Python", + "lang": "Python", + "source": "import os\n\nfrom scalar_api import ScalarApi\n\nclient = ScalarApi(\n bearer_auth=os.environ.get(\"BEARER_AUTH\"),\n)\n\nlogin_portal = client.login_portals.delete(\n slug=\"slug\",\n idempotency_key=\"\",\n)\nprint(login_portal)" + }, + { + "label": "Go", + "lang": "Go", + "source": "package main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"os\"\n\n\tsdk \"scalar-api\"\n\t\"scalar-api/option\"\n)\n\nfunc main() {\n\tclient := sdk.NewClient(\n\t\toption.WithBearerAuth(os.Getenv(\"BEARER_AUTH\")),\n\t)\n\n\tloginPortal, err := client.LoginPortals.Delete(context.Background(), \"slug\")\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tfmt.Println(loginPortal)\n}" + }, + { + "label": "Kotlin", + "lang": "Kotlin", + "source": "import com.scalar.api.client.ScalarApiClient\nimport com.scalar.api.client.okhttp.ScalarApiOkHttpClient\nimport com.scalar.api.models.loginportals.LoginPortalDeleteParams\n\nval client: ScalarApiClient = ScalarApiOkHttpClient.builder()\n .bearerAuth(System.getenv(\"BEARER_AUTH\"))\n .build()\n\nval params = LoginPortalDeleteParams.builder()\n .slug(\"slug\")\n .build()\nval loginPortal = client.loginPortals().delete(params)\nprintln(loginPortal)" + }, + { + "label": "Ruby", + "lang": "Ruby", + "source": "require \"json\"\nrequire \"scalar-api\"\n\nclient = ScalarApi::Client.new(\n bearer_auth: ENV[\"BEARER_AUTH\"],\n)\n\nresponse = client.loginPortals.delete(\"smoke-test\")\nputs response.inspect" + }, + { + "label": "Java", + "lang": "Java", + "source": "import com.scalar.api.client.ScalarApiClient;\nimport com.scalar.api.client.okhttp.ScalarApiOkHttpClient;\nimport com.scalar.api.models.loginportals.LoginPortalDeleteParams;\n\nScalarApiClient client = ScalarApiOkHttpClient.builder()\n .bearerAuth(System.getenv(\"BEARER_AUTH\"))\n .build();\n\nLoginPortalDeleteParams params = LoginPortalDeleteParams.builder()\n .slug(\"slug\")\n .build();\nvar loginPortal = client.loginPortals().delete(params);\nSystem.out.println(loginPortal);" + }, + { + "lang": "Shell", + "label": "CLI", + "source": "scalarapi login-portals delete 'slug' --bearer-auth \"$BEARER_AUTH\"" + } + ] + } + }, + "/v1/login-portals": { + "post": { + "tags": [ + "Login Portals" + ], + "description": "Create a login portal for the current team.", + "summary": "Create a portal", + "operationId": "createLoginPortal", + "responses": { + "200": { + "description": "Default Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/uid" + } + } + } + }, + "400": { + "description": "Bad request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/400" + } + } + } + }, + "401": { + "description": "No auth", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/401" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/403" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/404" + } + } + } + }, + "422": { + "description": "Invalid payload", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/422" + } + } + } + }, + "500": { + "description": "Uncaught error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/500" + } + } + } + } + }, + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "title": { + "type": "string" + }, + "slug": { + "type": "string" + }, + "email": { + "$ref": "#/components/schemas/login-portal-email" + }, + "page": { + "$ref": "#/components/schemas/login-portal-page" + } + }, + "required": [ + "title", + "slug", + "email", + "page" + ], + "additionalProperties": false + } + } + }, + "required": true + }, + "x-codeSamples": [ + { + "label": "TypeScript", + "lang": "TypeScript", + "source": "import ScalarAPI from \"@scalar/sdk\";\n\nconst client = new ScalarAPI({\n bearerAuth: process.env[\"BEARER_AUTH\"], // defaults to the BEARER_AUTH env var\n environment: \"production\",\n});\n\nconst uID = await client.loginPortals.create({\n title: \"\",\n slug: \"\",\n email: {\n logo: \"\",\n logoSize: \"100\",\n buttonText: \"Login\",\n message: \"Click to access private documentation hosted by scalar.com\",\n title: \"Private Docs\",\n mainColor: \"#2a2f45\",\n mainBackground: \"#f6f6f6\",\n cardColor: \"2a2f45\",\n cardBackground: \"#fff\",\n buttonColor: \"#fff\",\n buttonBackground: \"#0f0f0f\",\n },\n page: {\n title: \"Scalar Private Docs\",\n description: \"Login to access your documentation\",\n head: \"\",\n script: \"\",\n theme: \"\",\n companyName: \"\",\n logo: \"\",\n logoUrl: \"\",\n favicon: \"\",\n termsLink: \"\",\n privacyLink: \"\",\n formTitle: \"Scalar Private Docs\",\n formDescription: \"Login to access your documentation\",\n formImage: \"\",\n },\n});\nconsole.log(uID);" + }, + { + "label": "Shell", + "lang": "Shell", + "source": "scalarapi login-portals create --bearer-auth \"$BEARER_AUTH\" --title 'title' --slug 'slug' --email '{\"logo\":\"\",\"logoSize\":\"100\",\"buttonText\":\"Login\",\"message\":\"Click to access private documentation hosted by scalar.com\",\"title\":\"Private Docs\",\"mainColor\":\"#2a2f45\",\"mainBackground\":\"#f6f6f6\",\"cardColor\":\"2a2f45\",\"cardBackground\":\"#fff\",\"buttonColor\":\"#fff\",\"buttonBackground\":\"#0f0f0f\"}' --page '{\"title\":\"Scalar Private Docs\",\"description\":\"Login to access your documentation\",\"head\":\"\",\"script\":\"\",\"theme\":\"\",\"companyName\":\"\",\"logo\":\"\",\"logoURL\":\"\",\"favicon\":\"\",\"termsLink\":\"\",\"privacyLink\":\"\",\"formTitle\":\"Scalar Private Docs\",\"formDescription\":\"Login to access your documentation\",\"formImage\":\"\"}'" + }, + { + "label": "Python", + "lang": "Python", + "source": "import os\n\nfrom scalar_api import ScalarApi\n\nclient = ScalarApi(\n bearer_auth=os.environ.get(\"BEARER_AUTH\"),\n)\n\nlogin_portal = client.login_portals.create(\n title=\"\",\n slug=\"\",\n email={\"logo\": \"\", \"logo_size\": \"100\", \"button_text\": \"Login\", \"message\": \"Click to access private documentation hosted by scalar.com\", \"title\": \"Private Docs\", \"main_color\": \"#2a2f45\", \"main_background\": \"#f6f6f6\", \"card_color\": \"2a2f45\", \"card_background\": \"#fff\", \"button_color\": \"#fff\", \"button_background\": \"#0f0f0f\"},\n page={\"title\": \"Scalar Private Docs\", \"description\": \"Login to access your documentation\", \"head\": \"\", \"script\": \"\", \"theme\": \"\", \"company_name\": \"\", \"logo\": \"\", \"logo_url\": \"\", \"favicon\": \"\", \"terms_link\": \"\", \"privacy_link\": \"\", \"form_title\": \"Scalar Private Docs\", \"form_description\": \"Login to access your documentation\", \"form_image\": \"\"},\n idempotency_key=\"\",\n)\nprint(login_portal)" + }, + { + "label": "Go", + "lang": "Go", + "source": "package main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"os\"\n\n\tsdk \"scalar-api\"\n\t\"scalar-api/option\"\n)\n\nfunc main() {\n\tclient := sdk.NewClient(\n\t\toption.WithBearerAuth(os.Getenv(\"BEARER_AUTH\")),\n\t)\n\n\tloginPortal, err := client.LoginPortals.New(context.Background(), sdk.LoginPortalNewParams{\n\t\tEmail: sdk.LoginPortalEmail{\n\t\t\tLogo: \"\",\n\t\t\tLogoSize: \"100\",\n\t\t\tButtonText: \"Login\",\n\t\t\tMessage: \"Click to access private documentation hosted by scalar.com\",\n\t\t\tTitle: \"Private Docs\",\n\t\t\tMainColor: \"#2a2f45\",\n\t\t\tMainBackground: \"#f6f6f6\",\n\t\t\tCardColor: \"2a2f45\",\n\t\t\tCardBackground: \"#fff\",\n\t\t\tButtonColor: \"#fff\",\n\t\t\tButtonBackground: \"#0f0f0f\",\n\t\t},\n\t\tPage: sdk.LoginPortalPage{\n\t\t\tTitle: \"Scalar Private Docs\",\n\t\t\tDescription: \"Login to access your documentation\",\n\t\t\tHead: \"\",\n\t\t\tScript: \"\",\n\t\t\tTheme: \"\",\n\t\t\tCompanyName: \"\",\n\t\t\tLogo: \"\",\n\t\t\tLogoURL: \"\",\n\t\t\tFavicon: \"\",\n\t\t\tTermsLink: \"\",\n\t\t\tPrivacyLink: \"\",\n\t\t\tFormTitle: \"Scalar Private Docs\",\n\t\t\tFormDescription: \"Login to access your documentation\",\n\t\t\tFormImage: \"\",\n\t\t},\n\t\tSlug: \"\",\n\t\tTitle: \"\",\n\t})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tfmt.Println(loginPortal)\n}" + }, + { + "label": "Kotlin", + "lang": "Kotlin", + "source": "import com.scalar.api.client.ScalarApiClient\nimport com.scalar.api.client.okhttp.ScalarApiOkHttpClient\nimport com.scalar.api.models.loginportals.LoginPortalCreateParams\nimport com.scalar.api.models.loginportals.LoginPortalEmail\nimport com.scalar.api.models.loginportals.LoginPortalPage\n\nval client: ScalarApiClient = ScalarApiOkHttpClient.builder()\n .bearerAuth(System.getenv(\"BEARER_AUTH\"))\n .build()\n\nval params = LoginPortalCreateParams.builder()\n .title(\"title\")\n .slug(\"slug\")\n .email(LoginPortalEmail.builder()\n .logo(\"\")\n .logoSize(\"100\")\n .buttonText(\"Login\")\n .message(\"Click to access private documentation hosted by scalar.com\")\n .title(\"Private Docs\")\n .mainColor(\"#2a2f45\")\n .mainBackground(\"#f6f6f6\")\n .cardColor(\"2a2f45\")\n .cardBackground(\"#fff\")\n .buttonColor(\"#fff\")\n .buttonBackground(\"#0f0f0f\")\n .build())\n .page(LoginPortalPage.builder()\n .title(\"Scalar Private Docs\")\n .description(\"Login to access your documentation\")\n .head(\"\")\n .script(\"\")\n .theme(\"\")\n .companyName(\"\")\n .logo(\"\")\n .logoUrl(\"\")\n .favicon(\"\")\n .termsLink(\"\")\n .privacyLink(\"\")\n .formTitle(\"Scalar Private Docs\")\n .formDescription(\"Login to access your documentation\")\n .formImage(\"\")\n .build())\n .build()\nval loginPortal = client.loginPortals().create(params)\nprintln(loginPortal)" + }, + { + "label": "Ruby", + "lang": "Ruby", + "source": "require \"json\"\nrequire \"scalar-api\"\n\nclient = ScalarApi::Client.new(\n bearer_auth: ENV[\"BEARER_AUTH\"],\n)\n\nresponse = client.loginPortals.create({ title: \"title\", slug: \"slug\", email: \"email\", page: \"page\" })\nputs response.inspect" + }, + { + "label": "Java", + "lang": "Java", + "source": "import com.scalar.api.client.ScalarApiClient;\nimport com.scalar.api.client.okhttp.ScalarApiOkHttpClient;\nimport com.scalar.api.models.loginportals.LoginPortalCreateParams;\nimport com.scalar.api.models.loginportals.LoginPortalEmail;\nimport com.scalar.api.models.loginportals.LoginPortalPage;\n\nScalarApiClient client = ScalarApiOkHttpClient.builder()\n .bearerAuth(System.getenv(\"BEARER_AUTH\"))\n .build();\n\nLoginPortalCreateParams params = LoginPortalCreateParams.builder()\n .title(\"title\")\n .slug(\"slug\")\n .email(LoginPortalEmail.builder()\n .logo(\"\")\n .logoSize(\"100\")\n .buttonText(\"Login\")\n .message(\"Click to access private documentation hosted by scalar.com\")\n .title(\"Private Docs\")\n .mainColor(\"#2a2f45\")\n .mainBackground(\"#f6f6f6\")\n .cardColor(\"2a2f45\")\n .cardBackground(\"#fff\")\n .buttonColor(\"#fff\")\n .buttonBackground(\"#0f0f0f\")\n .build())\n .page(LoginPortalPage.builder()\n .title(\"Scalar Private Docs\")\n .description(\"Login to access your documentation\")\n .head(\"\")\n .script(\"\")\n .theme(\"\")\n .companyName(\"\")\n .logo(\"\")\n .logoUrl(\"\")\n .favicon(\"\")\n .termsLink(\"\")\n .privacyLink(\"\")\n .formTitle(\"Scalar Private Docs\")\n .formDescription(\"Login to access your documentation\")\n .formImage(\"\")\n .build())\n .build();\nvar loginPortal = client.loginPortals().create(params);\nSystem.out.println(loginPortal);" + }, + { + "lang": "Shell", + "label": "CLI", + "source": "scalarapi login-portals create --bearer-auth \"$BEARER_AUTH\" --title 'title' --slug 'slug' --email '{\"logo\":\"\",\"logoSize\":\"100\",\"buttonText\":\"Login\",\"message\":\"Click to access private documentation hosted by scalar.com\",\"title\":\"Private Docs\",\"mainColor\":\"#2a2f45\",\"mainBackground\":\"#f6f6f6\",\"cardColor\":\"2a2f45\",\"cardBackground\":\"#fff\",\"buttonColor\":\"#fff\",\"buttonBackground\":\"#0f0f0f\"}' --page '{\"title\":\"Scalar Private Docs\",\"description\":\"Login to access your documentation\",\"head\":\"\",\"script\":\"\",\"theme\":\"\",\"companyName\":\"\",\"logo\":\"\",\"logoURL\":\"\",\"favicon\":\"\",\"termsLink\":\"\",\"privacyLink\":\"\",\"formTitle\":\"Scalar Private Docs\",\"formDescription\":\"Login to access your documentation\",\"formImage\":\"\"}'" + } + ] + }, + "get": { + "tags": [ + "Login Portals" + ], + "description": "List all login portals for the current team.", + "summary": "List all portals", + "operationId": "listLoginPortals", + "responses": { + "200": { + "description": "Default Response", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/login-portal" + } + } + } + } + }, + "400": { + "description": "Bad request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/400" + } + } + } + }, + "401": { + "description": "No auth", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/401" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/403" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/404" + } + } + } + }, + "422": { + "description": "Invalid payload", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/422" + } + } + } + }, + "500": { + "description": "Uncaught error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/500" + } + } + } + } + }, + "x-codeSamples": [ + { + "label": "TypeScript", + "lang": "TypeScript", + "source": "import ScalarAPI from \"@scalar/sdk\";\n\nconst client = new ScalarAPI({\n bearerAuth: process.env[\"BEARER_AUTH\"], // defaults to the BEARER_AUTH env var\n environment: \"production\",\n});\n\nconst list = await client.loginPortals.list();\nconsole.log(list);" + }, + { + "label": "Shell", + "lang": "Shell", + "source": "scalarapi login-portals list --bearer-auth \"$BEARER_AUTH\"" + }, + { + "label": "Python", + "lang": "Python", + "source": "import os\n\nfrom scalar_api import ScalarApi\n\nclient = ScalarApi(\n bearer_auth=os.environ.get(\"BEARER_AUTH\"),\n)\n\nlogin_portal = client.login_portals.list()\nprint(login_portal)" + }, + { + "label": "Go", + "lang": "Go", + "source": "package main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"os\"\n\n\tsdk \"scalar-api\"\n\t\"scalar-api/option\"\n)\n\nfunc main() {\n\tclient := sdk.NewClient(\n\t\toption.WithBearerAuth(os.Getenv(\"BEARER_AUTH\")),\n\t)\n\n\tloginPortal, err := client.LoginPortals.List(context.Background())\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tfmt.Println(loginPortal)\n}" + }, + { + "label": "Kotlin", + "lang": "Kotlin", + "source": "import com.scalar.api.client.ScalarApiClient\nimport com.scalar.api.client.okhttp.ScalarApiOkHttpClient\nimport com.scalar.api.models.loginportals.LoginPortalListParams\n\nval client: ScalarApiClient = ScalarApiOkHttpClient.builder()\n .bearerAuth(System.getenv(\"BEARER_AUTH\"))\n .build()\n\nval loginPortal = client.loginPortals().list(LoginPortalListParams.none())\nprintln(loginPortal)" + }, + { + "label": "Ruby", + "lang": "Ruby", + "source": "require \"json\"\nrequire \"scalar-api\"\n\nclient = ScalarApi::Client.new(\n bearer_auth: ENV[\"BEARER_AUTH\"],\n)\n\nresponse = client.loginPortals.list\nputs response.inspect" + }, + { + "label": "Java", + "lang": "Java", + "source": "import com.scalar.api.client.ScalarApiClient;\nimport com.scalar.api.client.okhttp.ScalarApiOkHttpClient;\nimport com.scalar.api.models.loginportals.LoginPortalListParams;\n\nScalarApiClient client = ScalarApiOkHttpClient.builder()\n .bearerAuth(System.getenv(\"BEARER_AUTH\"))\n .build();\n\nvar loginPortal = client.loginPortals().list();\nSystem.out.println(loginPortal);" + }, + { + "lang": "Shell", + "label": "CLI", + "source": "scalarapi login-portals list --bearer-auth \"$BEARER_AUTH\"" + } + ] + } + }, + "/v1/rulesets/{namespace}": { + "get": { + "tags": [ + "Rules" + ], + "description": "List all rulesets in a namespace.", + "summary": "List all rules", + "operationId": "listRulesets", + "responses": { + "200": { + "description": "Default Response", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/rule" + } + } + } + } + }, + "400": { + "description": "Bad request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/400" + } + } + } + }, + "401": { + "description": "No auth", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/401" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/403" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/404" + } + } + } + }, + "422": { + "description": "Invalid payload", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/422" + } + } + } + }, + "500": { + "description": "Uncaught error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/500" + } + } + } + } + }, + "parameters": [ + { + "schema": { + "type": "string" + }, + "in": "path", + "name": "namespace", + "required": true + } + ], + "x-codeSamples": [ + { + "label": "TypeScript", + "lang": "TypeScript", + "source": "import ScalarAPI from \"@scalar/sdk\";\n\nconst client = new ScalarAPI({\n bearerAuth: process.env[\"BEARER_AUTH\"], // defaults to the BEARER_AUTH env var\n environment: \"production\",\n});\n\nconst listRulesets = await client.rules.listRulesets(\"namespace\");\nconsole.log(listRulesets);" + }, + { + "label": "Shell", + "lang": "Shell", + "source": "scalarapi rules list-rulesets 'namespace' --bearer-auth \"$BEARER_AUTH\"" + }, + { + "label": "Python", + "lang": "Python", + "source": "import os\n\nfrom scalar_api import ScalarApi\n\nclient = ScalarApi(\n bearer_auth=os.environ.get(\"BEARER_AUTH\"),\n)\n\nrule = client.rules.list_rulesets(\n namespace=\"namespace\",\n)\nprint(rule)" + }, + { + "label": "Go", + "lang": "Go", + "source": "package main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"os\"\n\n\tsdk \"scalar-api\"\n\t\"scalar-api/option\"\n)\n\nfunc main() {\n\tclient := sdk.NewClient(\n\t\toption.WithBearerAuth(os.Getenv(\"BEARER_AUTH\")),\n\t)\n\n\trule, err := client.Rules.ListRulesets(context.Background(), \"namespace\")\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tfmt.Println(rule)\n}" + }, + { + "label": "Kotlin", + "lang": "Kotlin", + "source": "import com.scalar.api.client.ScalarApiClient\nimport com.scalar.api.client.okhttp.ScalarApiOkHttpClient\nimport com.scalar.api.models.rules.RuleListRulesetsParams\n\nval client: ScalarApiClient = ScalarApiOkHttpClient.builder()\n .bearerAuth(System.getenv(\"BEARER_AUTH\"))\n .build()\n\nval params = RuleListRulesetsParams.builder()\n .namespace(\"namespace\")\n .build()\nval rule = client.rules().listRulesets(params)\nprintln(rule)" + }, + { + "label": "Ruby", + "lang": "Ruby", + "source": "require \"json\"\nrequire \"scalar-api\"\n\nclient = ScalarApi::Client.new(\n bearer_auth: ENV[\"BEARER_AUTH\"],\n)\n\nresponse = client.rules.list_rulesets(\"smoke-test\")\nputs response.inspect" + }, + { + "label": "Java", + "lang": "Java", + "source": "import com.scalar.api.client.ScalarApiClient;\nimport com.scalar.api.client.okhttp.ScalarApiOkHttpClient;\nimport com.scalar.api.models.rules.RuleListRulesetsParams;\n\nScalarApiClient client = ScalarApiOkHttpClient.builder()\n .bearerAuth(System.getenv(\"BEARER_AUTH\"))\n .build();\n\nRuleListRulesetsParams params = RuleListRulesetsParams.builder()\n .namespace(\"namespace\")\n .build();\nvar rule = client.rules().listRulesets(params);\nSystem.out.println(rule);" + }, + { + "lang": "Shell", + "label": "CLI", + "source": "scalarapi rules list-rulesets 'namespace' --bearer-auth \"$BEARER_AUTH\"" + } + ] + }, + "post": { + "tags": [ + "Rules" + ], + "description": "Create a rule in a namespace.", + "summary": "Create a rule", + "operationId": "createRuleset", + "responses": { + "200": { + "description": "Default Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/uid" + } + } + } + }, + "400": { + "description": "Bad request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/400" + } + } + } + }, + "401": { + "description": "No auth", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/401" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/403" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/404" + } + } + } + }, + "422": { + "description": "Invalid payload", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/422" + } + } + } + }, + "500": { + "description": "Uncaught error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/500" + } + } + } + } + }, + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "title": { + "type": "string" + }, + "description": { + "type": "string" + }, + "slug": { + "type": "string" + }, + "isPrivate": { + "type": "boolean" + }, + "document": { + "type": "string" + } + }, + "required": [ + "title", + "slug", + "document" + ], + "additionalProperties": false + } + } + }, + "required": true + }, + "parameters": [ + { + "schema": { + "type": "string" + }, + "in": "path", + "name": "namespace", + "required": true + } + ], + "x-codeSamples": [ + { + "label": "TypeScript", + "lang": "TypeScript", + "source": "import ScalarAPI from \"@scalar/sdk\";\n\nconst client = new ScalarAPI({\n bearerAuth: process.env[\"BEARER_AUTH\"], // defaults to the BEARER_AUTH env var\n environment: \"production\",\n});\n\nconst uID = await client.rules.createRuleset(\"namespace\", {\n title: \"\",\n slug: \"\",\n document: \"\",\n});\nconsole.log(uID);" + }, + { + "label": "Shell", + "lang": "Shell", + "source": "scalarapi rules create-ruleset 'namespace' --bearer-auth \"$BEARER_AUTH\" --title 'title' --slug 'slug' --document 'document'" + }, + { + "label": "Python", + "lang": "Python", + "source": "import os\n\nfrom scalar_api import ScalarApi\n\nclient = ScalarApi(\n bearer_auth=os.environ.get(\"BEARER_AUTH\"),\n)\n\nrule = client.rules.create_ruleset(\n namespace=\"namespace\",\n title=\"\",\n slug=\"\",\n document=\"\",\n idempotency_key=\"\",\n)\nprint(rule)" + }, + { + "label": "Go", + "lang": "Go", + "source": "package main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"os\"\n\n\tsdk \"scalar-api\"\n\t\"scalar-api/option\"\n)\n\nfunc main() {\n\tclient := sdk.NewClient(\n\t\toption.WithBearerAuth(os.Getenv(\"BEARER_AUTH\")),\n\t)\n\n\trule, err := client.Rules.NewRuleset(context.Background(), \"namespace\", sdk.RuleNewRulesetParams{\n\t\tDocument: \"\",\n\t\tSlug: \"\",\n\t\tTitle: \"\",\n\t})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tfmt.Println(rule)\n}" + }, + { + "label": "Kotlin", + "lang": "Kotlin", + "source": "import com.scalar.api.client.ScalarApiClient\nimport com.scalar.api.client.okhttp.ScalarApiOkHttpClient\nimport com.scalar.api.models.rules.RuleCreateRulesetParams\n\nval client: ScalarApiClient = ScalarApiOkHttpClient.builder()\n .bearerAuth(System.getenv(\"BEARER_AUTH\"))\n .build()\n\nval params = RuleCreateRulesetParams.builder()\n .namespace(\"namespace\")\n .title(\"title\")\n .slug(\"slug\")\n .document(\"document\")\n .build()\nval rule = client.rules().createRuleset(params)\nprintln(rule)" + }, + { + "label": "Ruby", + "lang": "Ruby", + "source": "require \"json\"\nrequire \"scalar-api\"\n\nclient = ScalarApi::Client.new(\n bearer_auth: ENV[\"BEARER_AUTH\"],\n)\n\nresponse = client.rules.create_ruleset(\"smoke-test\", { title: \"title\", description: \"description\", slug: \"slug\", is_private: \"is_private\", document: \"document\" })\nputs response.inspect" + }, + { + "label": "Java", + "lang": "Java", + "source": "import com.scalar.api.client.ScalarApiClient;\nimport com.scalar.api.client.okhttp.ScalarApiOkHttpClient;\nimport com.scalar.api.models.rules.RuleCreateRulesetParams;\n\nScalarApiClient client = ScalarApiOkHttpClient.builder()\n .bearerAuth(System.getenv(\"BEARER_AUTH\"))\n .build();\n\nRuleCreateRulesetParams params = RuleCreateRulesetParams.builder()\n .namespace(\"namespace\")\n .title(\"title\")\n .slug(\"slug\")\n .document(\"document\")\n .build();\nvar rule = client.rules().createRuleset(params);\nSystem.out.println(rule);" + }, + { + "lang": "Shell", + "label": "CLI", + "source": "scalarapi rules create-ruleset 'namespace' --bearer-auth \"$BEARER_AUTH\" --title 'title' --slug 'slug' --document 'document'" + } + ] + } + }, + "/v1/rulesets/{namespace}/{slug}": { + "patch": { + "tags": [ + "Rules" + ], + "description": "Update rule metadata by slug.", + "summary": "Update rule metadata", + "operationId": "updateRuleset", + "responses": { + "200": { + "description": "Default Response", + "content": { + "application/json": { + "schema": { + "type": "null" + } + } + } + }, + "400": { + "description": "Bad request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/400" + } + } + } + }, + "401": { + "description": "No auth", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/401" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/403" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/404" + } + } + } + }, + "422": { + "description": "Invalid payload", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/422" + } + } + } + }, + "500": { + "description": "Uncaught error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/500" + } + } + } + } + }, + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "namespace": { + "type": "string" + }, + "slug": { + "type": "string" + }, + "title": { + "type": "string" + }, + "description": { + "type": "string" + }, + "isPrivate": { + "type": "boolean" + } + }, + "additionalProperties": false + } + } + }, + "required": true + }, + "parameters": [ + { + "schema": { + "type": "string" + }, + "in": "path", + "name": "namespace", + "required": true + }, + { + "schema": { + "type": "string" + }, + "in": "path", + "name": "slug", + "required": true + } + ], + "x-codeSamples": [ + { + "label": "TypeScript", + "lang": "TypeScript", + "source": "import ScalarAPI from \"@scalar/sdk\";\n\nconst client = new ScalarAPI({\n bearerAuth: process.env[\"BEARER_AUTH\"], // defaults to the BEARER_AUTH env var\n environment: \"production\",\n});\n\nawait client.rules.updateRuleset(\"slug\", {\n namespace: \"namespace\",\n});" + }, + { + "label": "Shell", + "lang": "Shell", + "source": "scalarapi rules update-ruleset 'slug' --bearer-auth \"$BEARER_AUTH\" --namespace 'namespace'" + }, + { + "label": "Python", + "lang": "Python", + "source": "import os\n\nfrom scalar_api import ScalarApi\n\nclient = ScalarApi(\n bearer_auth=os.environ.get(\"BEARER_AUTH\"),\n)\n\nrule = client.rules.update_ruleset(\n namespace=\"namespace\",\n slug=\"slug\",\n idempotency_key=\"\",\n)\nprint(rule)" + }, + { + "label": "Go", + "lang": "Go", + "source": "package main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"os\"\n\n\tsdk \"scalar-api\"\n\t\"scalar-api/option\"\n)\n\nfunc main() {\n\tclient := sdk.NewClient(\n\t\toption.WithBearerAuth(os.Getenv(\"BEARER_AUTH\")),\n\t)\n\n\trule, err := client.Rules.UpdateRuleset(context.Background(), \"namespace\", \"slug\", sdk.RuleUpdateRulesetParams{})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tfmt.Println(rule)\n}" + }, + { + "label": "Kotlin", + "lang": "Kotlin", + "source": "import com.scalar.api.client.ScalarApiClient\nimport com.scalar.api.client.okhttp.ScalarApiOkHttpClient\nimport com.scalar.api.models.rules.RuleUpdateRulesetParams\n\nval client: ScalarApiClient = ScalarApiOkHttpClient.builder()\n .bearerAuth(System.getenv(\"BEARER_AUTH\"))\n .build()\n\nval params = RuleUpdateRulesetParams.builder()\n .namespace(\"namespace\")\n .slug(\"slug\")\n .build()\nval rule = client.rules().updateRuleset(params)\nprintln(rule)" + }, + { + "label": "Ruby", + "lang": "Ruby", + "source": "require \"json\"\nrequire \"scalar-api\"\n\nclient = ScalarApi::Client.new(\n bearer_auth: ENV[\"BEARER_AUTH\"],\n)\n\nresponse = client.rules.update_ruleset(\"smoke-test\", { namespace: \"namespace\", namespace_2: \"namespace_2\", slug_2: \"slug_2\", title: \"title\", description: \"description\", is_private: \"is_private\" })\nputs response.inspect" + }, + { + "label": "Java", + "lang": "Java", + "source": "import com.scalar.api.client.ScalarApiClient;\nimport com.scalar.api.client.okhttp.ScalarApiOkHttpClient;\nimport com.scalar.api.models.rules.RuleUpdateRulesetParams;\n\nScalarApiClient client = ScalarApiOkHttpClient.builder()\n .bearerAuth(System.getenv(\"BEARER_AUTH\"))\n .build();\n\nRuleUpdateRulesetParams params = RuleUpdateRulesetParams.builder()\n .namespace(\"namespace\")\n .slug(\"slug\")\n .build();\nvar rule = client.rules().updateRuleset(params);\nSystem.out.println(rule);" + }, + { + "lang": "Shell", + "label": "CLI", + "source": "scalarapi rules update-ruleset 'slug' --bearer-auth \"$BEARER_AUTH\" --namespace 'namespace'" + } + ] + }, + "delete": { + "tags": [ + "Rules" + ], + "description": "Delete a rule by slug.", + "summary": "Delete a rule", + "operationId": "deleteRuleset", + "responses": { + "200": { + "description": "Default Response", + "content": { + "application/json": { + "schema": { + "type": "null" + } + } + } + }, + "400": { + "description": "Bad request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/400" + } + } + } + }, + "401": { + "description": "No auth", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/401" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/403" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/404" + } + } + } + }, + "422": { + "description": "Invalid payload", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/422" + } + } + } + }, + "500": { + "description": "Uncaught error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/500" + } + } + } + } + }, + "parameters": [ + { + "schema": { + "type": "string" + }, + "in": "path", + "name": "namespace", + "required": true + }, + { + "schema": { + "type": "string" + }, + "in": "path", + "name": "slug", + "required": true + } + ], + "x-codeSamples": [ + { + "label": "TypeScript", + "lang": "TypeScript", + "source": "import ScalarAPI from \"@scalar/sdk\";\n\nconst client = new ScalarAPI({\n bearerAuth: process.env[\"BEARER_AUTH\"], // defaults to the BEARER_AUTH env var\n environment: \"production\",\n});\n\nawait client.rules.deleteRuleset(\"slug\", {\n namespace: \"namespace\",\n});" + }, + { + "label": "Shell", + "lang": "Shell", + "source": "scalarapi rules delete-ruleset 'slug' --bearer-auth \"$BEARER_AUTH\" --namespace 'namespace'" + }, + { + "label": "Python", + "lang": "Python", + "source": "import os\n\nfrom scalar_api import ScalarApi\n\nclient = ScalarApi(\n bearer_auth=os.environ.get(\"BEARER_AUTH\"),\n)\n\nrule = client.rules.delete_ruleset(\n namespace=\"namespace\",\n slug=\"slug\",\n idempotency_key=\"\",\n)\nprint(rule)" + }, + { + "label": "Go", + "lang": "Go", + "source": "package main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"os\"\n\n\tsdk \"scalar-api\"\n\t\"scalar-api/option\"\n)\n\nfunc main() {\n\tclient := sdk.NewClient(\n\t\toption.WithBearerAuth(os.Getenv(\"BEARER_AUTH\")),\n\t)\n\n\trule, err := client.Rules.DeleteRuleset(context.Background(), \"namespace\", \"slug\")\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tfmt.Println(rule)\n}" + }, + { + "label": "Kotlin", + "lang": "Kotlin", + "source": "import com.scalar.api.client.ScalarApiClient\nimport com.scalar.api.client.okhttp.ScalarApiOkHttpClient\nimport com.scalar.api.models.rules.RuleDeleteRulesetParams\n\nval client: ScalarApiClient = ScalarApiOkHttpClient.builder()\n .bearerAuth(System.getenv(\"BEARER_AUTH\"))\n .build()\n\nval params = RuleDeleteRulesetParams.builder()\n .namespace(\"namespace\")\n .slug(\"slug\")\n .build()\nval rule = client.rules().deleteRuleset(params)\nprintln(rule)" + }, + { + "label": "Ruby", + "lang": "Ruby", + "source": "require \"json\"\nrequire \"scalar-api\"\n\nclient = ScalarApi::Client.new(\n bearer_auth: ENV[\"BEARER_AUTH\"],\n)\n\nresponse = client.rules.delete_ruleset(\"smoke-test\", { namespace: \"namespace\" })\nputs response.inspect" + }, + { + "label": "Java", + "lang": "Java", + "source": "import com.scalar.api.client.ScalarApiClient;\nimport com.scalar.api.client.okhttp.ScalarApiOkHttpClient;\nimport com.scalar.api.models.rules.RuleDeleteRulesetParams;\n\nScalarApiClient client = ScalarApiOkHttpClient.builder()\n .bearerAuth(System.getenv(\"BEARER_AUTH\"))\n .build();\n\nRuleDeleteRulesetParams params = RuleDeleteRulesetParams.builder()\n .namespace(\"namespace\")\n .slug(\"slug\")\n .build();\nvar rule = client.rules().deleteRuleset(params);\nSystem.out.println(rule);" + }, + { + "lang": "Shell", + "label": "CLI", + "source": "scalarapi rules delete-ruleset 'slug' --bearer-auth \"$BEARER_AUTH\" --namespace 'namespace'" + } + ] + }, + "get": { + "tags": [ + "Rules" + ], + "description": "Get a rule document by slug.", + "summary": "Get a rule", + "operationId": "getRulesetDocument", + "responses": { + "200": { + "description": "Default Response", + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + } + }, + "400": { + "description": "Bad request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/400" + } + } + } + }, + "401": { + "description": "No auth", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/401" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/403" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/404" + } + } + } + }, + "422": { + "description": "Invalid payload", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/422" + } + } + } + }, + "500": { + "description": "Uncaught error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/500" + } + } + } + } + }, + "parameters": [ + { + "schema": { + "type": "string" + }, + "in": "path", + "name": "namespace", + "required": true + }, + { + "schema": { + "type": "string" + }, + "in": "path", + "name": "slug", + "required": true + } + ], + "x-codeSamples": [ + { + "label": "TypeScript", + "lang": "TypeScript", + "source": "import ScalarAPI from \"@scalar/sdk\";\n\nconst client = new ScalarAPI({\n bearerAuth: process.env[\"BEARER_AUTH\"], // defaults to the BEARER_AUTH env var\n environment: \"production\",\n});\n\nconst string_ = await client.rules.retrieveRulesetDocument(\"slug\", {\n namespace: \"namespace\",\n});\nconsole.log(string_);" + }, + { + "label": "Shell", + "lang": "Shell", + "source": "scalarapi rules retrieve-ruleset-document 'slug' --bearer-auth \"$BEARER_AUTH\" --namespace 'namespace'" + }, + { + "label": "Python", + "lang": "Python", + "source": "import os\n\nfrom scalar_api import ScalarApi\n\nclient = ScalarApi(\n bearer_auth=os.environ.get(\"BEARER_AUTH\"),\n)\n\nrule = client.rules.retrieve_ruleset_document(\n namespace=\"namespace\",\n slug=\"slug\",\n)\nprint(rule)" + }, + { + "label": "Go", + "lang": "Go", + "source": "package main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"os\"\n\n\tsdk \"scalar-api\"\n\t\"scalar-api/option\"\n)\n\nfunc main() {\n\tclient := sdk.NewClient(\n\t\toption.WithBearerAuth(os.Getenv(\"BEARER_AUTH\")),\n\t)\n\n\trule, err := client.Rules.GetRulesetDocument(context.Background(), \"namespace\", \"slug\")\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tfmt.Println(rule)\n}" + }, + { + "label": "Kotlin", + "lang": "Kotlin", + "source": "import com.scalar.api.client.ScalarApiClient\nimport com.scalar.api.client.okhttp.ScalarApiOkHttpClient\nimport com.scalar.api.models.rules.RuleRetrieveRulesetDocumentParams\n\nval client: ScalarApiClient = ScalarApiOkHttpClient.builder()\n .bearerAuth(System.getenv(\"BEARER_AUTH\"))\n .build()\n\nval params = RuleRetrieveRulesetDocumentParams.builder()\n .namespace(\"namespace\")\n .slug(\"slug\")\n .build()\nval rule = client.rules().retrieveRulesetDocument(params)\nprintln(rule)" + }, + { + "label": "Ruby", + "lang": "Ruby", + "source": "require \"json\"\nrequire \"scalar-api\"\n\nclient = ScalarApi::Client.new(\n bearer_auth: ENV[\"BEARER_AUTH\"],\n)\n\nresponse = client.rules.retrieve_ruleset_document(\"smoke-test\", { namespace: \"namespace\" })\nputs response.inspect" + }, + { + "label": "Java", + "lang": "Java", + "source": "import com.scalar.api.client.ScalarApiClient;\nimport com.scalar.api.client.okhttp.ScalarApiOkHttpClient;\nimport com.scalar.api.models.rules.RuleRetrieveRulesetDocumentParams;\n\nScalarApiClient client = ScalarApiOkHttpClient.builder()\n .bearerAuth(System.getenv(\"BEARER_AUTH\"))\n .build();\n\nRuleRetrieveRulesetDocumentParams params = RuleRetrieveRulesetDocumentParams.builder()\n .namespace(\"namespace\")\n .slug(\"slug\")\n .build();\nvar rule = client.rules().retrieveRulesetDocument(params);\nSystem.out.println(rule);" + }, + { + "lang": "Shell", + "label": "CLI", + "source": "scalarapi rules retrieve-ruleset-document 'slug' --bearer-auth \"$BEARER_AUTH\" --namespace 'namespace'" + } + ] + } + }, + "/v1/rulesets/{namespace}/{slug}/access-group": { + "post": { + "tags": [ + "Rules" + ], + "description": "Grant an access group to a rule.", + "summary": "Add rule access group", + "operationId": "addRulesetAccessGroup", + "responses": { + "200": { + "description": "Default Response", + "content": { + "application/json": { + "schema": { + "type": "null" + } + } + } + }, + "400": { + "description": "Bad request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/400" + } + } + } + }, + "401": { + "description": "No auth", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/401" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/403" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/404" + } + } + } + }, + "422": { + "description": "Invalid payload", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/422" + } + } + } + }, + "500": { + "description": "Uncaught error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/500" + } + } + } + } + }, + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/access-group" + } + } + }, + "required": true + }, + "parameters": [ + { + "schema": { + "type": "string" + }, + "in": "path", + "name": "namespace", + "required": true + }, + { + "schema": { + "type": "string" + }, + "in": "path", + "name": "slug", + "required": true + } + ], + "x-codeSamples": [ + { + "label": "TypeScript", + "lang": "TypeScript", + "source": "import ScalarAPI from \"@scalar/sdk\";\n\nconst client = new ScalarAPI({\n bearerAuth: process.env[\"BEARER_AUTH\"], // defaults to the BEARER_AUTH env var\n environment: \"production\",\n});\n\nawait client.rules.createRulesetAccessGroup(\"slug\", {\n namespace: \"namespace\",\n accessGroupSlug: \"\",\n});" + }, + { + "label": "Shell", + "lang": "Shell", + "source": "scalarapi rules create-ruleset-access-group 'slug' --bearer-auth \"$BEARER_AUTH\" --namespace 'namespace' --access-group-slug 'accessGroupSlug'" + }, + { + "label": "Python", + "lang": "Python", + "source": "import os\n\nfrom scalar_api import ScalarApi\n\nclient = ScalarApi(\n bearer_auth=os.environ.get(\"BEARER_AUTH\"),\n)\n\nrule = client.rules.create_ruleset_access_group(\n namespace=\"namespace\",\n slug=\"slug\",\n access_group_slug=\"\",\n idempotency_key=\"\",\n)\nprint(rule)" + }, + { + "label": "Go", + "lang": "Go", + "source": "package main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"os\"\n\n\tsdk \"scalar-api\"\n\t\"scalar-api/option\"\n)\n\nfunc main() {\n\tclient := sdk.NewClient(\n\t\toption.WithBearerAuth(os.Getenv(\"BEARER_AUTH\")),\n\t)\n\n\trule, err := client.Rules.NewRulesetAccessGroup(context.Background(), \"namespace\", \"slug\", sdk.RuleNewRulesetAccessGroupParams{\n\t\tAccessGroup: sdk.AccessGroup{\n\t\tAccessGroupSlug: \"\",\n\t},\n\t})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tfmt.Println(rule)\n}" + }, + { + "label": "Kotlin", + "lang": "Kotlin", + "source": "import com.scalar.api.client.ScalarApiClient\nimport com.scalar.api.client.okhttp.ScalarApiOkHttpClient\nimport com.scalar.api.models.rules.RuleCreateRulesetAccessGroupParams\n\nval client: ScalarApiClient = ScalarApiOkHttpClient.builder()\n .bearerAuth(System.getenv(\"BEARER_AUTH\"))\n .build()\n\nval params = RuleCreateRulesetAccessGroupParams.builder()\n .namespace(\"namespace\")\n .slug(\"slug\")\n .accessGroupSlug(\"accessGroupSlug\")\n .build()\nval rule = client.rules().createRulesetAccessGroup(params)\nprintln(rule)" + }, + { + "label": "Ruby", + "lang": "Ruby", + "source": "require \"json\"\nrequire \"scalar-api\"\n\nclient = ScalarApi::Client.new(\n bearer_auth: ENV[\"BEARER_AUTH\"],\n)\n\nresponse = client.rules.create_ruleset_access_group(\"smoke-test\", { namespace: \"namespace\", access_group_slug: \"access_group_slug\" })\nputs response.inspect" + }, + { + "label": "Java", + "lang": "Java", + "source": "import com.scalar.api.client.ScalarApiClient;\nimport com.scalar.api.client.okhttp.ScalarApiOkHttpClient;\nimport com.scalar.api.models.rules.RuleCreateRulesetAccessGroupParams;\n\nScalarApiClient client = ScalarApiOkHttpClient.builder()\n .bearerAuth(System.getenv(\"BEARER_AUTH\"))\n .build();\n\nRuleCreateRulesetAccessGroupParams params = RuleCreateRulesetAccessGroupParams.builder()\n .namespace(\"namespace\")\n .slug(\"slug\")\n .accessGroupSlug(\"accessGroupSlug\")\n .build();\nvar rule = client.rules().createRulesetAccessGroup(params);\nSystem.out.println(rule);" + }, + { + "lang": "Shell", + "label": "CLI", + "source": "scalarapi rules create-ruleset-access-group 'slug' --bearer-auth \"$BEARER_AUTH\" --namespace 'namespace' --access-group-slug 'accessGroupSlug'" + } + ] + }, + "delete": { + "tags": [ + "Rules" + ], + "description": "Remove an access group from a rule.", + "summary": "Remove rule access group", + "operationId": "removeRulesetAccessGroup", + "responses": { + "200": { + "description": "Default Response", + "content": { + "application/json": { + "schema": { + "type": "null" + } + } + } + }, + "400": { + "description": "Bad request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/400" + } + } + } + }, + "401": { + "description": "No auth", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/401" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/403" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/404" + } + } + } + }, + "422": { + "description": "Invalid payload", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/422" + } + } + } + }, + "500": { + "description": "Uncaught error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/500" + } + } + } + } + }, + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/access-group" + } + } + }, + "required": true + }, + "parameters": [ + { + "schema": { + "type": "string" + }, + "in": "path", + "name": "namespace", + "required": true + }, + { + "schema": { + "type": "string" + }, + "in": "path", + "name": "slug", + "required": true + } + ], + "x-codeSamples": [ + { + "label": "TypeScript", + "lang": "TypeScript", + "source": "import ScalarAPI from \"@scalar/sdk\";\n\nconst client = new ScalarAPI({\n bearerAuth: process.env[\"BEARER_AUTH\"], // defaults to the BEARER_AUTH env var\n environment: \"production\",\n});\n\nawait client.rules.deleteRulesetAccessGroup(\"slug\", {\n namespace: \"namespace\",\n accessGroupSlug: \"\",\n});" + }, + { + "label": "Shell", + "lang": "Shell", + "source": "scalarapi rules delete-ruleset-access-group 'slug' --bearer-auth \"$BEARER_AUTH\" --namespace 'namespace' --access-group-slug 'accessGroupSlug'" + }, + { + "label": "Python", + "lang": "Python", + "source": "import os\n\nfrom scalar_api import ScalarApi\n\nclient = ScalarApi(\n bearer_auth=os.environ.get(\"BEARER_AUTH\"),\n)\n\nrule = client.rules.delete_ruleset_access_group(\n namespace=\"namespace\",\n slug=\"slug\",\n access_group_slug=\"\",\n idempotency_key=\"\",\n)\nprint(rule)" + }, + { + "label": "Go", + "lang": "Go", + "source": "package main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"os\"\n\n\tsdk \"scalar-api\"\n\t\"scalar-api/option\"\n)\n\nfunc main() {\n\tclient := sdk.NewClient(\n\t\toption.WithBearerAuth(os.Getenv(\"BEARER_AUTH\")),\n\t)\n\n\trule, err := client.Rules.DeleteRulesetAccessGroup(context.Background(), \"namespace\", \"slug\", sdk.RuleDeleteRulesetAccessGroupParams{\n\t\tAccessGroup: sdk.AccessGroup{\n\t\tAccessGroupSlug: \"\",\n\t},\n\t})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tfmt.Println(rule)\n}" + }, + { + "label": "Kotlin", + "lang": "Kotlin", + "source": "import com.scalar.api.client.ScalarApiClient\nimport com.scalar.api.client.okhttp.ScalarApiOkHttpClient\nimport com.scalar.api.models.rules.RuleDeleteRulesetAccessGroupParams\n\nval client: ScalarApiClient = ScalarApiOkHttpClient.builder()\n .bearerAuth(System.getenv(\"BEARER_AUTH\"))\n .build()\n\nval params = RuleDeleteRulesetAccessGroupParams.builder()\n .namespace(\"namespace\")\n .slug(\"slug\")\n .accessGroupSlug(\"accessGroupSlug\")\n .build()\nval rule = client.rules().deleteRulesetAccessGroup(params)\nprintln(rule)" + }, + { + "label": "Ruby", + "lang": "Ruby", + "source": "require \"json\"\nrequire \"scalar-api\"\n\nclient = ScalarApi::Client.new(\n bearer_auth: ENV[\"BEARER_AUTH\"],\n)\n\nresponse = client.rules.delete_ruleset_access_group(\"smoke-test\", { namespace: \"namespace\", access_group_slug: \"access_group_slug\" })\nputs response.inspect" + }, + { + "label": "Java", + "lang": "Java", + "source": "import com.scalar.api.client.ScalarApiClient;\nimport com.scalar.api.client.okhttp.ScalarApiOkHttpClient;\nimport com.scalar.api.models.rules.RuleDeleteRulesetAccessGroupParams;\n\nScalarApiClient client = ScalarApiOkHttpClient.builder()\n .bearerAuth(System.getenv(\"BEARER_AUTH\"))\n .build();\n\nRuleDeleteRulesetAccessGroupParams params = RuleDeleteRulesetAccessGroupParams.builder()\n .namespace(\"namespace\")\n .slug(\"slug\")\n .accessGroupSlug(\"accessGroupSlug\")\n .build();\nvar rule = client.rules().deleteRulesetAccessGroup(params);\nSystem.out.println(rule);" + }, + { + "lang": "Shell", + "label": "CLI", + "source": "scalarapi rules delete-ruleset-access-group 'slug' --bearer-auth \"$BEARER_AUTH\" --namespace 'namespace' --access-group-slug 'accessGroupSlug'" + } + ] + } + }, + "/v1/themes": { + "get": { + "tags": [ + "Themes" + ], + "description": "List all team themes.", + "summary": "List all themes", + "operationId": "listThemes", + "responses": { + "200": { + "description": "Default Response", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/theme" + } + } + } + } + }, + "400": { + "description": "Bad request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/400" + } + } + } + }, + "401": { + "description": "No auth", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/401" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/403" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/404" + } + } + } + }, + "422": { + "description": "Invalid payload", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/422" + } + } + } + }, + "500": { + "description": "Uncaught error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/500" + } + } + } + } + }, + "x-codeSamples": [ + { + "label": "TypeScript", + "lang": "TypeScript", + "source": "import ScalarAPI from \"@scalar/sdk\";\n\nconst client = new ScalarAPI({\n bearerAuth: process.env[\"BEARER_AUTH\"], // defaults to the BEARER_AUTH env var\n environment: \"production\",\n});\n\nconst list = await client.themes.list();\nconsole.log(list);" + }, + { + "label": "Shell", + "lang": "Shell", + "source": "scalarapi themes list --bearer-auth \"$BEARER_AUTH\"" + }, + { + "label": "Python", + "lang": "Python", + "source": "import os\n\nfrom scalar_api import ScalarApi\n\nclient = ScalarApi(\n bearer_auth=os.environ.get(\"BEARER_AUTH\"),\n)\n\ntheme = client.themes.list()\nprint(theme)" + }, + { + "label": "Go", + "lang": "Go", + "source": "package main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"os\"\n\n\tsdk \"scalar-api\"\n\t\"scalar-api/option\"\n)\n\nfunc main() {\n\tclient := sdk.NewClient(\n\t\toption.WithBearerAuth(os.Getenv(\"BEARER_AUTH\")),\n\t)\n\n\ttheme, err := client.Themes.List(context.Background())\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tfmt.Println(theme)\n}" + }, + { + "label": "Kotlin", + "lang": "Kotlin", + "source": "import com.scalar.api.client.ScalarApiClient\nimport com.scalar.api.client.okhttp.ScalarApiOkHttpClient\nimport com.scalar.api.models.themes.ThemeListParams\n\nval client: ScalarApiClient = ScalarApiOkHttpClient.builder()\n .bearerAuth(System.getenv(\"BEARER_AUTH\"))\n .build()\n\nval theme = client.themes().list(ThemeListParams.none())\nprintln(theme)" + }, + { + "label": "Ruby", + "lang": "Ruby", + "source": "require \"json\"\nrequire \"scalar-api\"\n\nclient = ScalarApi::Client.new(\n bearer_auth: ENV[\"BEARER_AUTH\"],\n)\n\nresponse = client.themes.list\nputs response.inspect" + }, + { + "label": "Java", + "lang": "Java", + "source": "import com.scalar.api.client.ScalarApiClient;\nimport com.scalar.api.client.okhttp.ScalarApiOkHttpClient;\nimport com.scalar.api.models.themes.ThemeListParams;\n\nScalarApiClient client = ScalarApiOkHttpClient.builder()\n .bearerAuth(System.getenv(\"BEARER_AUTH\"))\n .build();\n\nvar theme = client.themes().list();\nSystem.out.println(theme);" + }, + { + "lang": "Shell", + "label": "CLI", + "source": "scalarapi themes list --bearer-auth \"$BEARER_AUTH\"" + } + ] + }, + "post": { + "tags": [ + "Themes" + ], + "description": "Create a team theme.", + "summary": "Create a theme", + "operationId": "createTheme", + "responses": { + "200": { + "description": "Default Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/uid" + } + } + } + }, + "400": { + "description": "Bad request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/400" + } + } + } + }, + "401": { + "description": "No auth", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/401" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/403" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/404" + } + } + } + }, + "422": { + "description": "Invalid payload", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/422" + } + } + } + }, + "500": { + "description": "Uncaught error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/500" + } + } + } + } + }, + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "description": { + "type": "string" + }, + "slug": { + "type": "string" + }, + "document": { + "type": "string" + } + }, + "required": [ + "name", + "slug", + "document" + ], + "additionalProperties": false + } + } + }, + "required": true + }, + "x-codeSamples": [ + { + "label": "TypeScript", + "lang": "TypeScript", + "source": "import ScalarAPI from \"@scalar/sdk\";\n\nconst client = new ScalarAPI({\n bearerAuth: process.env[\"BEARER_AUTH\"], // defaults to the BEARER_AUTH env var\n environment: \"production\",\n});\n\nconst uID = await client.themes.create({\n name: \"\",\n slug: \"\",\n document: \"\",\n});\nconsole.log(uID);" + }, + { + "label": "Shell", + "lang": "Shell", + "source": "scalarapi themes create --bearer-auth \"$BEARER_AUTH\" --name 'name' --slug 'slug' --document 'document'" + }, + { + "label": "Python", + "lang": "Python", + "source": "import os\n\nfrom scalar_api import ScalarApi\n\nclient = ScalarApi(\n bearer_auth=os.environ.get(\"BEARER_AUTH\"),\n)\n\ntheme = client.themes.create(\n name=\"\",\n slug=\"\",\n document=\"\",\n idempotency_key=\"\",\n)\nprint(theme)" + }, + { + "label": "Go", + "lang": "Go", + "source": "package main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"os\"\n\n\tsdk \"scalar-api\"\n\t\"scalar-api/option\"\n)\n\nfunc main() {\n\tclient := sdk.NewClient(\n\t\toption.WithBearerAuth(os.Getenv(\"BEARER_AUTH\")),\n\t)\n\n\ttheme, err := client.Themes.New(context.Background(), sdk.ThemeNewParams{\n\t\tDocument: \"\",\n\t\tName: \"\",\n\t\tSlug: \"\",\n\t})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tfmt.Println(theme)\n}" + }, + { + "label": "Kotlin", + "lang": "Kotlin", + "source": "import com.scalar.api.client.ScalarApiClient\nimport com.scalar.api.client.okhttp.ScalarApiOkHttpClient\nimport com.scalar.api.models.themes.ThemeCreateParams\n\nval client: ScalarApiClient = ScalarApiOkHttpClient.builder()\n .bearerAuth(System.getenv(\"BEARER_AUTH\"))\n .build()\n\nval params = ThemeCreateParams.builder()\n .name(\"name\")\n .slug(\"slug\")\n .document(\"document\")\n .build()\nval theme = client.themes().create(params)\nprintln(theme)" + }, + { + "label": "Ruby", + "lang": "Ruby", + "source": "require \"json\"\nrequire \"scalar-api\"\n\nclient = ScalarApi::Client.new(\n bearer_auth: ENV[\"BEARER_AUTH\"],\n)\n\nresponse = client.themes.create({ name: \"name\", description: \"description\", slug: \"slug\", document: \"document\" })\nputs response.inspect" + }, + { + "label": "Java", + "lang": "Java", + "source": "import com.scalar.api.client.ScalarApiClient;\nimport com.scalar.api.client.okhttp.ScalarApiOkHttpClient;\nimport com.scalar.api.models.themes.ThemeCreateParams;\n\nScalarApiClient client = ScalarApiOkHttpClient.builder()\n .bearerAuth(System.getenv(\"BEARER_AUTH\"))\n .build();\n\nThemeCreateParams params = ThemeCreateParams.builder()\n .name(\"name\")\n .slug(\"slug\")\n .document(\"document\")\n .build();\nvar theme = client.themes().create(params);\nSystem.out.println(theme);" + }, + { + "lang": "Shell", + "label": "CLI", + "source": "scalarapi themes create --bearer-auth \"$BEARER_AUTH\" --name 'name' --slug 'slug' --document 'document'" + } + ] + } + }, + "/v1/themes/{slug}": { + "patch": { + "tags": [ + "Themes" + ], + "description": "Update theme metadata.", + "summary": "Update theme metadata", + "operationId": "updateTheme", + "responses": { + "200": { + "description": "Default Response", + "content": { + "application/json": { + "schema": { + "type": "null" + } + } + } + }, + "400": { + "description": "Bad request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/400" + } + } + } + }, + "401": { + "description": "No auth", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/401" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/403" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/404" + } + } + } + }, + "422": { + "description": "Invalid payload", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/422" + } + } + } + }, + "500": { + "description": "Uncaught error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/500" + } + } + } + } + }, + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "description": { + "type": "string" + } + }, + "additionalProperties": false + } + } + }, + "required": true + }, + "parameters": [ + { + "schema": { + "type": "string" + }, + "in": "path", + "name": "slug", + "required": true + } + ], + "x-codeSamples": [ + { + "label": "TypeScript", + "lang": "TypeScript", + "source": "import ScalarAPI from \"@scalar/sdk\";\n\nconst client = new ScalarAPI({\n bearerAuth: process.env[\"BEARER_AUTH\"], // defaults to the BEARER_AUTH env var\n environment: \"production\",\n});\n\nawait client.themes.update(\"slug\", {});" + }, + { + "label": "Shell", + "lang": "Shell", + "source": "scalarapi themes update 'slug' --bearer-auth \"$BEARER_AUTH\"" + }, + { + "label": "Python", + "lang": "Python", + "source": "import os\n\nfrom scalar_api import ScalarApi\n\nclient = ScalarApi(\n bearer_auth=os.environ.get(\"BEARER_AUTH\"),\n)\n\ntheme = client.themes.update(\n slug=\"slug\",\n idempotency_key=\"\",\n)\nprint(theme)" + }, + { + "label": "Go", + "lang": "Go", + "source": "package main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"os\"\n\n\tsdk \"scalar-api\"\n\t\"scalar-api/option\"\n)\n\nfunc main() {\n\tclient := sdk.NewClient(\n\t\toption.WithBearerAuth(os.Getenv(\"BEARER_AUTH\")),\n\t)\n\n\ttheme, err := client.Themes.Update(context.Background(), \"slug\", sdk.ThemeUpdateParams{})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tfmt.Println(theme)\n}" + }, + { + "label": "Kotlin", + "lang": "Kotlin", + "source": "import com.scalar.api.client.ScalarApiClient\nimport com.scalar.api.client.okhttp.ScalarApiOkHttpClient\nimport com.scalar.api.models.themes.ThemeUpdateParams\n\nval client: ScalarApiClient = ScalarApiOkHttpClient.builder()\n .bearerAuth(System.getenv(\"BEARER_AUTH\"))\n .build()\n\nval params = ThemeUpdateParams.builder()\n .slug(\"slug\")\n .build()\nval theme = client.themes().update(params)\nprintln(theme)" + }, + { + "label": "Ruby", + "lang": "Ruby", + "source": "require \"json\"\nrequire \"scalar-api\"\n\nclient = ScalarApi::Client.new(\n bearer_auth: ENV[\"BEARER_AUTH\"],\n)\n\nresponse = client.themes.update(\"smoke-test\", { name: \"name\", description: \"description\" })\nputs response.inspect" + }, + { + "label": "Java", + "lang": "Java", + "source": "import com.scalar.api.client.ScalarApiClient;\nimport com.scalar.api.client.okhttp.ScalarApiOkHttpClient;\nimport com.scalar.api.models.themes.ThemeUpdateParams;\n\nScalarApiClient client = ScalarApiOkHttpClient.builder()\n .bearerAuth(System.getenv(\"BEARER_AUTH\"))\n .build();\n\nThemeUpdateParams params = ThemeUpdateParams.builder()\n .slug(\"slug\")\n .build();\nvar theme = client.themes().update(params);\nSystem.out.println(theme);" + }, + { + "lang": "Shell", + "label": "CLI", + "source": "scalarapi themes update 'slug' --bearer-auth \"$BEARER_AUTH\"" + } + ] + }, + "put": { + "tags": [ + "Themes" + ], + "description": "Replace the theme document.", + "summary": "Update theme document", + "operationId": "replaceThemeDocument", + "responses": { + "200": { + "description": "Default Response", + "content": { + "application/json": { + "schema": { + "type": "null" + } + } + } + }, + "400": { + "description": "Bad request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/400" + } + } + } + }, + "401": { + "description": "No auth", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/401" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/403" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/404" + } + } + } + }, + "422": { + "description": "Invalid payload", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/422" + } + } + } + }, + "500": { + "description": "Uncaught error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/500" + } + } + } + } + }, + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "document": { + "type": "string" + } + }, + "required": [ + "document" + ], + "additionalProperties": false + } + } + }, + "required": true + }, + "parameters": [ + { + "schema": { + "type": "string" + }, + "in": "path", + "name": "slug", + "required": true + } + ], + "x-codeSamples": [ + { + "label": "TypeScript", + "lang": "TypeScript", + "source": "import ScalarAPI from \"@scalar/sdk\";\n\nconst client = new ScalarAPI({\n bearerAuth: process.env[\"BEARER_AUTH\"], // defaults to the BEARER_AUTH env var\n environment: \"production\",\n});\n\nawait client.themes.replaceDocument(\"slug\", {\n document: \"\",\n});" + }, + { + "label": "Shell", + "lang": "Shell", + "source": "scalarapi themes replace-document 'slug' --bearer-auth \"$BEARER_AUTH\" --document 'document'" + }, + { + "label": "Python", + "lang": "Python", + "source": "import os\n\nfrom scalar_api import ScalarApi\n\nclient = ScalarApi(\n bearer_auth=os.environ.get(\"BEARER_AUTH\"),\n)\n\ntheme = client.themes.replace_document(\n slug=\"slug\",\n document=\"\",\n idempotency_key=\"\",\n)\nprint(theme)" + }, + { + "label": "Go", + "lang": "Go", + "source": "package main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"os\"\n\n\tsdk \"scalar-api\"\n\t\"scalar-api/option\"\n)\n\nfunc main() {\n\tclient := sdk.NewClient(\n\t\toption.WithBearerAuth(os.Getenv(\"BEARER_AUTH\")),\n\t)\n\n\ttheme, err := client.Themes.ReplaceDocument(context.Background(), \"slug\", sdk.ThemeReplaceDocumentParams{\n\t\tDocument: \"\",\n\t})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tfmt.Println(theme)\n}" + }, + { + "label": "Kotlin", + "lang": "Kotlin", + "source": "import com.scalar.api.client.ScalarApiClient\nimport com.scalar.api.client.okhttp.ScalarApiOkHttpClient\nimport com.scalar.api.models.themes.ThemeReplaceDocumentParams\n\nval client: ScalarApiClient = ScalarApiOkHttpClient.builder()\n .bearerAuth(System.getenv(\"BEARER_AUTH\"))\n .build()\n\nval params = ThemeReplaceDocumentParams.builder()\n .slug(\"slug\")\n .document(\"document\")\n .build()\nval theme = client.themes().replaceDocument(params)\nprintln(theme)" + }, + { + "label": "Ruby", + "lang": "Ruby", + "source": "require \"json\"\nrequire \"scalar-api\"\n\nclient = ScalarApi::Client.new(\n bearer_auth: ENV[\"BEARER_AUTH\"],\n)\n\nresponse = client.themes.replace_document(\"smoke-test\", { document: \"document\" })\nputs response.inspect" + }, + { + "label": "Java", + "lang": "Java", + "source": "import com.scalar.api.client.ScalarApiClient;\nimport com.scalar.api.client.okhttp.ScalarApiOkHttpClient;\nimport com.scalar.api.models.themes.ThemeReplaceDocumentParams;\n\nScalarApiClient client = ScalarApiOkHttpClient.builder()\n .bearerAuth(System.getenv(\"BEARER_AUTH\"))\n .build();\n\nThemeReplaceDocumentParams params = ThemeReplaceDocumentParams.builder()\n .slug(\"slug\")\n .document(\"document\")\n .build();\nvar theme = client.themes().replaceDocument(params);\nSystem.out.println(theme);" + }, + { + "lang": "Shell", + "label": "CLI", + "source": "scalarapi themes replace-document 'slug' --bearer-auth \"$BEARER_AUTH\" --document 'document'" + } + ] + }, + "delete": { + "tags": [ + "Themes" + ], + "description": "Delete a theme by slug.", + "summary": "Delete a theme", + "operationId": "deleteTheme", + "responses": { + "200": { + "description": "Default Response", + "content": { + "application/json": { + "schema": { + "type": "null" + } + } + } + }, + "400": { + "description": "Bad request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/400" + } + } + } + }, + "401": { + "description": "No auth", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/401" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/403" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/404" + } + } + } + }, + "422": { + "description": "Invalid payload", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/422" + } + } + } + }, + "500": { + "description": "Uncaught error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/500" + } + } + } + } + }, + "parameters": [ + { + "schema": { + "type": "string" + }, + "in": "path", + "name": "slug", + "required": true + } + ], + "x-codeSamples": [ + { + "label": "TypeScript", + "lang": "TypeScript", + "source": "import ScalarAPI from \"@scalar/sdk\";\n\nconst client = new ScalarAPI({\n bearerAuth: process.env[\"BEARER_AUTH\"], // defaults to the BEARER_AUTH env var\n environment: \"production\",\n});\n\nawait client.themes.delete(\"slug\");" + }, + { + "label": "Shell", + "lang": "Shell", + "source": "scalarapi themes delete 'slug' --bearer-auth \"$BEARER_AUTH\"" + }, + { + "label": "Python", + "lang": "Python", + "source": "import os\n\nfrom scalar_api import ScalarApi\n\nclient = ScalarApi(\n bearer_auth=os.environ.get(\"BEARER_AUTH\"),\n)\n\ntheme = client.themes.delete(\n slug=\"slug\",\n idempotency_key=\"\",\n)\nprint(theme)" + }, + { + "label": "Go", + "lang": "Go", + "source": "package main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"os\"\n\n\tsdk \"scalar-api\"\n\t\"scalar-api/option\"\n)\n\nfunc main() {\n\tclient := sdk.NewClient(\n\t\toption.WithBearerAuth(os.Getenv(\"BEARER_AUTH\")),\n\t)\n\n\ttheme, err := client.Themes.Delete(context.Background(), \"slug\")\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tfmt.Println(theme)\n}" + }, + { + "label": "Kotlin", + "lang": "Kotlin", + "source": "import com.scalar.api.client.ScalarApiClient\nimport com.scalar.api.client.okhttp.ScalarApiOkHttpClient\nimport com.scalar.api.models.themes.ThemeDeleteParams\n\nval client: ScalarApiClient = ScalarApiOkHttpClient.builder()\n .bearerAuth(System.getenv(\"BEARER_AUTH\"))\n .build()\n\nval params = ThemeDeleteParams.builder()\n .slug(\"slug\")\n .build()\nval theme = client.themes().delete(params)\nprintln(theme)" + }, + { + "label": "Ruby", + "lang": "Ruby", + "source": "require \"json\"\nrequire \"scalar-api\"\n\nclient = ScalarApi::Client.new(\n bearer_auth: ENV[\"BEARER_AUTH\"],\n)\n\nresponse = client.themes.delete(\"smoke-test\")\nputs response.inspect" + }, + { + "label": "Java", + "lang": "Java", + "source": "import com.scalar.api.client.ScalarApiClient;\nimport com.scalar.api.client.okhttp.ScalarApiOkHttpClient;\nimport com.scalar.api.models.themes.ThemeDeleteParams;\n\nScalarApiClient client = ScalarApiOkHttpClient.builder()\n .bearerAuth(System.getenv(\"BEARER_AUTH\"))\n .build();\n\nThemeDeleteParams params = ThemeDeleteParams.builder()\n .slug(\"slug\")\n .build();\nvar theme = client.themes().delete(params);\nSystem.out.println(theme);" + }, + { + "lang": "Shell", + "label": "CLI", + "source": "scalarapi themes delete 'slug' --bearer-auth \"$BEARER_AUTH\"" + } + ] + }, + "get": { + "tags": [ + "Themes" + ], + "description": "Get the theme document by slug.", + "summary": "Get a theme", + "operationId": "getTheme", + "responses": { + "200": { + "description": "Default Response", + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + } + }, + "400": { + "description": "Bad request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/400" + } + } + } + }, + "401": { + "description": "No auth", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/401" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/403" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/404" + } + } + } + }, + "422": { + "description": "Invalid payload", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/422" + } + } + } + }, + "500": { + "description": "Uncaught error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/500" + } + } + } + } + }, + "parameters": [ + { + "schema": { + "type": "string" + }, + "in": "path", + "name": "slug", + "required": true + } + ], + "x-codeSamples": [ + { + "label": "TypeScript", + "lang": "TypeScript", + "source": "import ScalarAPI from \"@scalar/sdk\";\n\nconst client = new ScalarAPI({\n bearerAuth: process.env[\"BEARER_AUTH\"], // defaults to the BEARER_AUTH env var\n environment: \"production\",\n});\n\nconst string_ = await client.themes.retrieve(\"slug\");\nconsole.log(string_);" + }, + { + "label": "Shell", + "lang": "Shell", + "source": "scalarapi themes retrieve 'slug' --bearer-auth \"$BEARER_AUTH\"" + }, + { + "label": "Python", + "lang": "Python", + "source": "import os\n\nfrom scalar_api import ScalarApi\n\nclient = ScalarApi(\n bearer_auth=os.environ.get(\"BEARER_AUTH\"),\n)\n\ntheme = client.themes.retrieve(\n slug=\"slug\",\n)\nprint(theme)" + }, + { + "label": "Go", + "lang": "Go", + "source": "package main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"os\"\n\n\tsdk \"scalar-api\"\n\t\"scalar-api/option\"\n)\n\nfunc main() {\n\tclient := sdk.NewClient(\n\t\toption.WithBearerAuth(os.Getenv(\"BEARER_AUTH\")),\n\t)\n\n\ttheme, err := client.Themes.Get(context.Background(), \"slug\")\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tfmt.Println(theme)\n}" + }, + { + "label": "Kotlin", + "lang": "Kotlin", + "source": "import com.scalar.api.client.ScalarApiClient\nimport com.scalar.api.client.okhttp.ScalarApiOkHttpClient\nimport com.scalar.api.models.themes.ThemeRetrieveParams\n\nval client: ScalarApiClient = ScalarApiOkHttpClient.builder()\n .bearerAuth(System.getenv(\"BEARER_AUTH\"))\n .build()\n\nval params = ThemeRetrieveParams.builder()\n .slug(\"slug\")\n .build()\nval theme = client.themes().retrieve(params)\nprintln(theme)" + }, + { + "label": "Ruby", + "lang": "Ruby", + "source": "require \"json\"\nrequire \"scalar-api\"\n\nclient = ScalarApi::Client.new(\n bearer_auth: ENV[\"BEARER_AUTH\"],\n)\n\nresponse = client.themes.retrieve(\"smoke-test\")\nputs response.inspect" + }, + { + "label": "Java", + "lang": "Java", + "source": "import com.scalar.api.client.ScalarApiClient;\nimport com.scalar.api.client.okhttp.ScalarApiOkHttpClient;\nimport com.scalar.api.models.themes.ThemeRetrieveParams;\n\nScalarApiClient client = ScalarApiOkHttpClient.builder()\n .bearerAuth(System.getenv(\"BEARER_AUTH\"))\n .build();\n\nThemeRetrieveParams params = ThemeRetrieveParams.builder()\n .slug(\"slug\")\n .build();\nvar theme = client.themes().retrieve(params);\nSystem.out.println(theme);" + }, + { + "lang": "Shell", + "label": "CLI", + "source": "scalarapi themes retrieve 'slug' --bearer-auth \"$BEARER_AUTH\"" + } + ] + } + }, + "/v1/teams": { + "get": { + "tags": [ + "Teams" + ], + "description": "List all available teams", + "summary": "List teams", + "operationId": "listTeams", + "responses": { + "200": { + "description": "Default Response", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/team" + } + } + } + } + }, + "400": { + "description": "Bad request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/400" + } + } + } + }, + "401": { + "description": "No auth", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/401" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/403" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/404" + } + } + } + }, + "422": { + "description": "Invalid payload", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/422" + } + } + } + }, + "500": { + "description": "Uncaught error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/500" + } + } + } + } + }, + "x-codeSamples": [ + { + "label": "TypeScript", + "lang": "TypeScript", + "source": "import ScalarAPI from \"@scalar/sdk\";\n\nconst client = new ScalarAPI({\n bearerAuth: process.env[\"BEARER_AUTH\"], // defaults to the BEARER_AUTH env var\n environment: \"production\",\n});\n\nconst list = await client.teams.list();\nconsole.log(list);" + }, + { + "label": "Shell", + "lang": "Shell", + "source": "scalarapi teams list --bearer-auth \"$BEARER_AUTH\"" + }, + { + "label": "Python", + "lang": "Python", + "source": "import os\n\nfrom scalar_api import ScalarApi\n\nclient = ScalarApi(\n bearer_auth=os.environ.get(\"BEARER_AUTH\"),\n)\n\nteam = client.teams.list()\nprint(team)" + }, + { + "label": "Go", + "lang": "Go", + "source": "package main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"os\"\n\n\tsdk \"scalar-api\"\n\t\"scalar-api/option\"\n)\n\nfunc main() {\n\tclient := sdk.NewClient(\n\t\toption.WithBearerAuth(os.Getenv(\"BEARER_AUTH\")),\n\t)\n\n\tteam, err := client.Teams.List(context.Background())\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tfmt.Println(team)\n}" + }, + { + "label": "Kotlin", + "lang": "Kotlin", + "source": "import com.scalar.api.client.ScalarApiClient\nimport com.scalar.api.client.okhttp.ScalarApiOkHttpClient\nimport com.scalar.api.models.teams.TeamListParams\n\nval client: ScalarApiClient = ScalarApiOkHttpClient.builder()\n .bearerAuth(System.getenv(\"BEARER_AUTH\"))\n .build()\n\nval team = client.teams().list(TeamListParams.none())\nprintln(team)" + }, + { + "label": "Ruby", + "lang": "Ruby", + "source": "require \"json\"\nrequire \"scalar-api\"\n\nclient = ScalarApi::Client.new(\n bearer_auth: ENV[\"BEARER_AUTH\"],\n)\n\nresponse = client.teams.list\nputs response.inspect" + }, + { + "label": "Java", + "lang": "Java", + "source": "import com.scalar.api.client.ScalarApiClient;\nimport com.scalar.api.client.okhttp.ScalarApiOkHttpClient;\nimport com.scalar.api.models.teams.TeamListParams;\n\nScalarApiClient client = ScalarApiOkHttpClient.builder()\n .bearerAuth(System.getenv(\"BEARER_AUTH\"))\n .build();\n\nvar team = client.teams().list();\nSystem.out.println(team);" + }, + { + "lang": "Shell", + "label": "CLI", + "source": "scalarapi teams list --bearer-auth \"$BEARER_AUTH\"" + } + ] + } + }, + "/v1/guides": { + "get": { + "tags": [ + "Scalar Docs" + ], + "description": "List all guide projects.", + "summary": "List all projects", + "operationId": "listGuides", + "responses": { + "200": { + "description": "Default Response", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/github-project" + } + } + } + } + }, + "400": { + "description": "Bad request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/400" + } + } + } + }, + "401": { + "description": "No auth", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/401" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/403" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/404" + } + } + } + }, + "422": { + "description": "Invalid payload", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/422" + } + } + } + }, + "500": { + "description": "Uncaught error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/500" + } + } + } + } + }, + "x-codeSamples": [ + { + "label": "TypeScript", + "lang": "TypeScript", + "source": "import ScalarAPI from \"@scalar/sdk\";\n\nconst client = new ScalarAPI({\n bearerAuth: process.env[\"BEARER_AUTH\"], // defaults to the BEARER_AUTH env var\n environment: \"production\",\n});\n\nconst listGuides = await client.scalarDocs.listGuides();\nconsole.log(listGuides);" + }, + { + "label": "Shell", + "lang": "Shell", + "source": "scalarapi scalar-docs list-guides --bearer-auth \"$BEARER_AUTH\"" + }, + { + "label": "Python", + "lang": "Python", + "source": "import os\n\nfrom scalar_api import ScalarApi\n\nclient = ScalarApi(\n bearer_auth=os.environ.get(\"BEARER_AUTH\"),\n)\n\nscalar_doc = client.scalar_docs.list_guides()\nprint(scalar_doc)" + }, + { + "label": "Go", + "lang": "Go", + "source": "package main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"os\"\n\n\tsdk \"scalar-api\"\n\t\"scalar-api/option\"\n)\n\nfunc main() {\n\tclient := sdk.NewClient(\n\t\toption.WithBearerAuth(os.Getenv(\"BEARER_AUTH\")),\n\t)\n\n\tscalarDoc, err := client.ScalarDocs.ListGuides(context.Background())\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tfmt.Println(scalarDoc)\n}" + }, + { + "label": "Kotlin", + "lang": "Kotlin", + "source": "import com.scalar.api.client.ScalarApiClient\nimport com.scalar.api.client.okhttp.ScalarApiOkHttpClient\nimport com.scalar.api.models.scalardocs.ScalarDocListGuidesParams\n\nval client: ScalarApiClient = ScalarApiOkHttpClient.builder()\n .bearerAuth(System.getenv(\"BEARER_AUTH\"))\n .build()\n\nval scalarDoc = client.scalarDocs().listGuides(ScalarDocListGuidesParams.none())\nprintln(scalarDoc)" + }, + { + "label": "Ruby", + "lang": "Ruby", + "source": "require \"json\"\nrequire \"scalar-api\"\n\nclient = ScalarApi::Client.new(\n bearer_auth: ENV[\"BEARER_AUTH\"],\n)\n\nresponse = client.scalarDocs.list_guides\nputs response.inspect" + }, + { + "label": "Java", + "lang": "Java", + "source": "import com.scalar.api.client.ScalarApiClient;\nimport com.scalar.api.client.okhttp.ScalarApiOkHttpClient;\nimport com.scalar.api.models.scalardocs.ScalarDocListGuidesParams;\n\nScalarApiClient client = ScalarApiOkHttpClient.builder()\n .bearerAuth(System.getenv(\"BEARER_AUTH\"))\n .build();\n\nvar scalarDoc = client.scalarDocs().listGuides();\nSystem.out.println(scalarDoc);" + }, + { + "lang": "Shell", + "label": "CLI", + "source": "scalarapi scalar-docs list-guides --bearer-auth \"$BEARER_AUTH\"" + } + ] + }, + "post": { + "tags": [ + "Scalar Docs" + ], + "description": "Create a guide project.", + "summary": "Create a project", + "operationId": "createGuide", + "responses": { + "200": { + "description": "Default Response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "uid": { + "type": "string" + }, + "slug": { + "type": "string" + } + }, + "required": [ + "uid", + "slug" + ], + "additionalProperties": false + } + } + } + }, + "400": { + "description": "Bad request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/400" + } + } + } + }, + "401": { + "description": "No auth", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/401" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/403" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/404" + } + } + } + }, + "422": { + "description": "Invalid payload", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/422" + } + } + } + }, + "500": { + "description": "Uncaught error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/500" + } + } + } + } + }, + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "slug": { + "$ref": "#/components/schemas/slug" + }, + "isPrivate": { + "default": false, + "type": "boolean" + }, + "allowedUsers": { + "default": [], + "type": "array", + "items": { + "type": "string" + } + }, + "allowedDomains": { + "default": [], + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "name", + "isPrivate", + "allowedUsers", + "allowedDomains" + ], + "additionalProperties": false + } + } + }, + "required": true + }, + "x-codeSamples": [ + { + "label": "TypeScript", + "lang": "TypeScript", + "source": "import ScalarAPI from \"@scalar/sdk\";\n\nconst client = new ScalarAPI({\n bearerAuth: process.env[\"BEARER_AUTH\"], // defaults to the BEARER_AUTH env var\n environment: \"production\",\n});\n\nconst createGuide = await client.scalarDocs.createGuide({\n name: \"\",\n isPrivate: false,\n allowedUsers: [],\n allowedDomains: [],\n});\nconsole.log(createGuide);" + }, + { + "label": "Shell", + "lang": "Shell", + "source": "scalarapi scalar-docs create-guide --bearer-auth \"$BEARER_AUTH\" --name 'name' --is-private" + }, + { + "label": "Python", + "lang": "Python", + "source": "import os\n\nfrom scalar_api import ScalarApi\n\nclient = ScalarApi(\n bearer_auth=os.environ.get(\"BEARER_AUTH\"),\n)\n\nscalar_doc = client.scalar_docs.create_guide(\n name=\"\",\n is_private=False,\n allowed_users=[],\n allowed_domains=[],\n idempotency_key=\"\",\n)\nprint(scalar_doc)" + }, + { + "label": "Go", + "lang": "Go", + "source": "package main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"os\"\n\n\tsdk \"scalar-api\"\n\t\"scalar-api/option\"\n)\n\nfunc main() {\n\tclient := sdk.NewClient(\n\t\toption.WithBearerAuth(os.Getenv(\"BEARER_AUTH\")),\n\t)\n\n\tscalarDoc, err := client.ScalarDocs.NewGuide(context.Background(), sdk.ScalarDocNewGuideParams{\n\t\tAllowedDomains: []string{\"\"},\n\t\tAllowedUsers: []string{\"\"},\n\t\tIsPrivate: false,\n\t\tName: \"\",\n\t})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tfmt.Println(scalarDoc)\n}" + }, + { + "label": "Kotlin", + "lang": "Kotlin", + "source": "import com.scalar.api.client.ScalarApiClient\nimport com.scalar.api.client.okhttp.ScalarApiOkHttpClient\nimport com.scalar.api.models.scalardocs.ScalarDocCreateGuideParams\n\nval client: ScalarApiClient = ScalarApiOkHttpClient.builder()\n .bearerAuth(System.getenv(\"BEARER_AUTH\"))\n .build()\n\nval params = ScalarDocCreateGuideParams.builder()\n .name(\"name\")\n .isPrivate(false)\n .allowedUsers(listOf(\"allowedUser\"))\n .allowedDomains(listOf(\"allowedDomain\"))\n .build()\nval scalarDoc = client.scalarDocs().createGuide(params)\nprintln(scalarDoc)" + }, + { + "label": "Ruby", + "lang": "Ruby", + "source": "require \"json\"\nrequire \"scalar-api\"\n\nclient = ScalarApi::Client.new(\n bearer_auth: ENV[\"BEARER_AUTH\"],\n)\n\nresponse = client.scalarDocs.create_guide({ name: \"name\", slug: \"slug\", is_private: \"is_private\", allowed_users: \"allowed_users\", allowed_domains: \"allowed_domains\" })\nputs response.inspect" + }, + { + "label": "Java", + "lang": "Java", + "source": "import com.scalar.api.client.ScalarApiClient;\nimport com.scalar.api.client.okhttp.ScalarApiOkHttpClient;\nimport com.scalar.api.models.scalardocs.ScalarDocCreateGuideParams;\n\nScalarApiClient client = ScalarApiOkHttpClient.builder()\n .bearerAuth(System.getenv(\"BEARER_AUTH\"))\n .build();\n\nScalarDocCreateGuideParams params = ScalarDocCreateGuideParams.builder()\n .name(\"name\")\n .isPrivate(false)\n .allowedUsers(java.util.List.of(\"allowedUser\"))\n .allowedDomains(java.util.List.of(\"allowedDomain\"))\n .build();\nvar scalarDoc = client.scalarDocs().createGuide(params);\nSystem.out.println(scalarDoc);" + }, + { + "lang": "Shell", + "label": "CLI", + "source": "scalarapi scalar-docs create-guide --bearer-auth \"$BEARER_AUTH\" --name 'name' --is-private" + } + ] + } + }, + "/v1/guides/{slug}/publish": { + "post": { + "tags": [ + "Scalar Docs" + ], + "description": "Start a new publish process.", + "summary": "Publish a project", + "operationId": "publishGuide", + "responses": { + "200": { + "description": "Default Response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "publishUid": { + "type": "string" + } + }, + "required": [ + "publishUid" + ], + "additionalProperties": false + } + } + } + }, + "400": { + "description": "Bad request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/400" + } + } + } + }, + "401": { + "description": "No auth", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/401" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/403" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/404" + } + } + } + }, + "422": { + "description": "Invalid payload", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/422" + } + } + } + }, + "500": { + "description": "Uncaught error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/500" + } + } + } + } + }, + "parameters": [ + { + "schema": { + "type": "string" + }, + "in": "path", + "name": "slug", + "required": true + } + ], + "x-codeSamples": [ + { + "label": "TypeScript", + "lang": "TypeScript", + "source": "import ScalarAPI from \"@scalar/sdk\";\n\nconst client = new ScalarAPI({\n bearerAuth: process.env[\"BEARER_AUTH\"], // defaults to the BEARER_AUTH env var\n environment: \"production\",\n});\n\nconst publishGuide = await client.scalarDocs.publishGuide(\"slug\");\nconsole.log(publishGuide);" + }, + { + "label": "Shell", + "lang": "Shell", + "source": "scalarapi scalar-docs publish-guide 'slug' --bearer-auth \"$BEARER_AUTH\"" + }, + { + "label": "Python", + "lang": "Python", + "source": "import os\n\nfrom scalar_api import ScalarApi\n\nclient = ScalarApi(\n bearer_auth=os.environ.get(\"BEARER_AUTH\"),\n)\n\nscalar_doc = client.scalar_docs.publish_guide(\n slug=\"slug\",\n idempotency_key=\"\",\n)\nprint(scalar_doc)" + }, + { + "label": "Go", + "lang": "Go", + "source": "package main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"os\"\n\n\tsdk \"scalar-api\"\n\t\"scalar-api/option\"\n)\n\nfunc main() {\n\tclient := sdk.NewClient(\n\t\toption.WithBearerAuth(os.Getenv(\"BEARER_AUTH\")),\n\t)\n\n\tscalarDoc, err := client.ScalarDocs.PublishGuide(context.Background(), \"slug\")\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tfmt.Println(scalarDoc)\n}" + }, + { + "label": "Kotlin", + "lang": "Kotlin", + "source": "import com.scalar.api.client.ScalarApiClient\nimport com.scalar.api.client.okhttp.ScalarApiOkHttpClient\nimport com.scalar.api.models.scalardocs.ScalarDocPublishGuideParams\n\nval client: ScalarApiClient = ScalarApiOkHttpClient.builder()\n .bearerAuth(System.getenv(\"BEARER_AUTH\"))\n .build()\n\nval params = ScalarDocPublishGuideParams.builder()\n .slug(\"slug\")\n .build()\nval scalarDoc = client.scalarDocs().publishGuide(params)\nprintln(scalarDoc)" + }, + { + "label": "Ruby", + "lang": "Ruby", + "source": "require \"json\"\nrequire \"scalar-api\"\n\nclient = ScalarApi::Client.new(\n bearer_auth: ENV[\"BEARER_AUTH\"],\n)\n\nresponse = client.scalarDocs.publish_guide(\"smoke-test\")\nputs response.inspect" + }, + { + "label": "Java", + "lang": "Java", + "source": "import com.scalar.api.client.ScalarApiClient;\nimport com.scalar.api.client.okhttp.ScalarApiOkHttpClient;\nimport com.scalar.api.models.scalardocs.ScalarDocPublishGuideParams;\n\nScalarApiClient client = ScalarApiOkHttpClient.builder()\n .bearerAuth(System.getenv(\"BEARER_AUTH\"))\n .build();\n\nScalarDocPublishGuideParams params = ScalarDocPublishGuideParams.builder()\n .slug(\"slug\")\n .build();\nvar scalarDoc = client.scalarDocs().publishGuide(params);\nSystem.out.println(scalarDoc);" + }, + { + "lang": "Shell", + "label": "CLI", + "source": "scalarapi scalar-docs publish-guide 'slug' --bearer-auth \"$BEARER_AUTH\"" + } + ] + } + }, + "/v1/namespaces": { + "get": { + "tags": [ + "Namespaces" + ], + "description": "Get all namespaces for the current team", + "summary": "List namespaces", + "operationId": "listNamespaces", + "responses": { + "200": { + "description": "Default Response", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + } + } + }, + "400": { + "description": "Bad request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/400" + } + } + } + }, + "401": { + "description": "No auth", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/401" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/403" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/404" + } + } + } + }, + "422": { + "description": "Invalid payload", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/422" + } + } + } + }, + "500": { + "description": "Uncaught error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/500" + } + } + } + } + }, + "x-codeSamples": [ + { + "label": "TypeScript", + "lang": "TypeScript", + "source": "import ScalarAPI from \"@scalar/sdk\";\n\nconst client = new ScalarAPI({\n bearerAuth: process.env[\"BEARER_AUTH\"], // defaults to the BEARER_AUTH env var\n environment: \"production\",\n});\n\nconst list = await client.namespaces.list();\nconsole.log(list);" + }, + { + "label": "Shell", + "lang": "Shell", + "source": "scalarapi namespaces list --bearer-auth \"$BEARER_AUTH\"" + }, + { + "label": "Python", + "lang": "Python", + "source": "import os\n\nfrom scalar_api import ScalarApi\n\nclient = ScalarApi(\n bearer_auth=os.environ.get(\"BEARER_AUTH\"),\n)\n\nnamespace = client.namespaces.list()\nprint(namespace)" + }, + { + "label": "Go", + "lang": "Go", + "source": "package main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"os\"\n\n\tsdk \"scalar-api\"\n\t\"scalar-api/option\"\n)\n\nfunc main() {\n\tclient := sdk.NewClient(\n\t\toption.WithBearerAuth(os.Getenv(\"BEARER_AUTH\")),\n\t)\n\n\tnamespace, err := client.Namespaces.List(context.Background())\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tfmt.Println(namespace)\n}" + }, + { + "label": "Kotlin", + "lang": "Kotlin", + "source": "import com.scalar.api.client.ScalarApiClient\nimport com.scalar.api.client.okhttp.ScalarApiOkHttpClient\nimport com.scalar.api.models.namespaces.NamespaceListParams\n\nval client: ScalarApiClient = ScalarApiOkHttpClient.builder()\n .bearerAuth(System.getenv(\"BEARER_AUTH\"))\n .build()\n\nval namespace = client.namespaces().list(NamespaceListParams.none())\nprintln(namespace)" + }, + { + "label": "Ruby", + "lang": "Ruby", + "source": "require \"json\"\nrequire \"scalar-api\"\n\nclient = ScalarApi::Client.new(\n bearer_auth: ENV[\"BEARER_AUTH\"],\n)\n\nresponse = client.namespace(\"namespace\").list\nputs response.inspect" + }, + { + "label": "Java", + "lang": "Java", + "source": "import com.scalar.api.client.ScalarApiClient;\nimport com.scalar.api.client.okhttp.ScalarApiOkHttpClient;\nimport com.scalar.api.models.namespaces.NamespaceListParams;\n\nScalarApiClient client = ScalarApiOkHttpClient.builder()\n .bearerAuth(System.getenv(\"BEARER_AUTH\"))\n .build();\n\nvar namespace = client.namespaces().list();\nSystem.out.println(namespace);" + }, + { + "lang": "Shell", + "label": "CLI", + "source": "scalarapi namespaces list --bearer-auth \"$BEARER_AUTH\"" + } + ] + } + }, + "/v1/auth/exchange": { + "post": { + "tags": [ + "Authentication" + ], + "description": "Exchange an API key for an access token.", + "summary": "Exchange token", + "operationId": "exchangePersonalToken", + "responses": { + "200": { + "description": "Default Response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "accessToken": { + "type": "string" + } + }, + "required": [ + "accessToken" + ], + "additionalProperties": false + } + } + } + }, + "400": { + "description": "Bad request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/400" + } + } + } + }, + "401": { + "description": "No auth", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/401" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/403" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/404" + } + } + } + }, + "422": { + "description": "Invalid payload", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/422" + } + } + } + }, + "500": { + "description": "Uncaught error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/500" + } + } + } + } + }, + "security": [], + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "personalToken": { + "type": "string" + } + }, + "required": [ + "personalToken" + ], + "additionalProperties": false + } + } + }, + "required": true + }, + "x-codeSamples": [ + { + "label": "TypeScript", + "lang": "TypeScript", + "source": "import ScalarAPI from \"@scalar/sdk\";\n\nconst client = new ScalarAPI({\n bearerAuth: process.env[\"BEARER_AUTH\"], // defaults to the BEARER_AUTH env var\n environment: \"production\",\n});\n\nconst exchangePersonalToken = await client.authentication.exchangePersonalToken({\n personalToken: \"\",\n});\nconsole.log(exchangePersonalToken);" + }, + { + "label": "Shell", + "lang": "Shell", + "source": "scalarapi authentication exchange-personal-token --bearer-auth \"$BEARER_AUTH\" --personal-token 'personalToken'" + }, + { + "label": "Python", + "lang": "Python", + "source": "import os\n\nfrom scalar_api import ScalarApi\n\nclient = ScalarApi(\n bearer_auth=os.environ.get(\"BEARER_AUTH\"),\n)\n\nauthentication = client.authentication.exchange_personal_token(\n personal_token=\"\",\n idempotency_key=\"\",\n)\nprint(authentication)" + }, + { + "label": "Go", + "lang": "Go", + "source": "package main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"os\"\n\n\tsdk \"scalar-api\"\n\t\"scalar-api/option\"\n)\n\nfunc main() {\n\tclient := sdk.NewClient(\n\t\toption.WithBearerAuth(os.Getenv(\"BEARER_AUTH\")),\n\t)\n\n\tauthentication, err := client.Authentication.ExchangePersonalToken(context.Background(), sdk.AuthenticationExchangePersonalTokenParams{\n\t\tPersonalToken: \"\",\n\t})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tfmt.Println(authentication)\n}" + }, + { + "label": "Kotlin", + "lang": "Kotlin", + "source": "import com.scalar.api.client.ScalarApiClient\nimport com.scalar.api.client.okhttp.ScalarApiOkHttpClient\nimport com.scalar.api.models.authentication.AuthenticationExchangePersonalTokenParams\n\nval client: ScalarApiClient = ScalarApiOkHttpClient.builder()\n .bearerAuth(System.getenv(\"BEARER_AUTH\"))\n .build()\n\nval params = AuthenticationExchangePersonalTokenParams.builder()\n .personalToken(\"personalToken\")\n .build()\nval authentication = client.authentication().exchangePersonalToken(params)\nprintln(authentication)" + }, + { + "label": "Ruby", + "lang": "Ruby", + "source": "require \"json\"\nrequire \"scalar-api\"\n\nclient = ScalarApi::Client.new(\n bearer_auth: ENV[\"BEARER_AUTH\"],\n)\n\nresponse = client.authentication.exchange_personal_token({ personal_token: \"personal_token\" })\nputs response.inspect" + }, + { + "label": "Java", + "lang": "Java", + "source": "import com.scalar.api.client.ScalarApiClient;\nimport com.scalar.api.client.okhttp.ScalarApiOkHttpClient;\nimport com.scalar.api.models.authentication.AuthenticationExchangePersonalTokenParams;\n\nScalarApiClient client = ScalarApiOkHttpClient.builder()\n .bearerAuth(System.getenv(\"BEARER_AUTH\"))\n .build();\n\nAuthenticationExchangePersonalTokenParams params = AuthenticationExchangePersonalTokenParams.builder()\n .personalToken(\"personalToken\")\n .build();\nvar authentication = client.authentication().exchangePersonalToken(params);\nSystem.out.println(authentication);" + }, + { + "lang": "Shell", + "label": "CLI", + "source": "scalarapi authentication exchange-personal-token --bearer-auth \"$BEARER_AUTH\" --personal-token 'personalToken'" + } + ] + } + }, + "/v1/auth/me": { + "get": { + "tags": [ + "Authentication" + ], + "description": "Get the authenticated user, including their available teams and theme.", + "summary": "Get current user", + "operationId": "getCurrentUser", + "responses": { + "200": { + "description": "Default Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/user" + } + } + } + }, + "400": { + "description": "Bad request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/400" + } + } + } + }, + "401": { + "description": "No auth", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/401" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/403" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/404" + } + } + } + }, + "422": { + "description": "Invalid payload", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/422" + } + } + } + }, + "500": { + "description": "Uncaught error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/500" + } + } + } + } + }, + "x-codeSamples": [ + { + "label": "TypeScript", + "lang": "TypeScript", + "source": "import ScalarAPI from \"@scalar/sdk\";\n\nconst client = new ScalarAPI({\n bearerAuth: process.env[\"BEARER_AUTH\"], // defaults to the BEARER_AUTH env var\n environment: \"production\",\n});\n\nconst user = await client.authentication.listCurrentUser();\nconsole.log(user);" + }, + { + "label": "Shell", + "lang": "Shell", + "source": "scalarapi authentication list-current-user --bearer-auth \"$BEARER_AUTH\"" + }, + { + "label": "Python", + "lang": "Python", + "source": "import os\n\nfrom scalar_api import ScalarApi\n\nclient = ScalarApi(\n bearer_auth=os.environ.get(\"BEARER_AUTH\"),\n)\n\nauthentication = client.authentication.list_current_user()\nprint(authentication)" + }, + { + "label": "Go", + "lang": "Go", + "source": "package main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"os\"\n\n\tsdk \"scalar-api\"\n\t\"scalar-api/option\"\n)\n\nfunc main() {\n\tclient := sdk.NewClient(\n\t\toption.WithBearerAuth(os.Getenv(\"BEARER_AUTH\")),\n\t)\n\n\tauthentication, err := client.Authentication.ListCurrentUser(context.Background())\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tfmt.Println(authentication)\n}" + }, + { + "label": "Kotlin", + "lang": "Kotlin", + "source": "import com.scalar.api.client.ScalarApiClient\nimport com.scalar.api.client.okhttp.ScalarApiOkHttpClient\nimport com.scalar.api.models.authentication.AuthenticationListCurrentUserParams\n\nval client: ScalarApiClient = ScalarApiOkHttpClient.builder()\n .bearerAuth(System.getenv(\"BEARER_AUTH\"))\n .build()\n\nval authentication = client.authentication().listCurrentUser(AuthenticationListCurrentUserParams.none())\nprintln(authentication)" + }, + { + "label": "Ruby", + "lang": "Ruby", + "source": "require \"json\"\nrequire \"scalar-api\"\n\nclient = ScalarApi::Client.new(\n bearer_auth: ENV[\"BEARER_AUTH\"],\n)\n\nresponse = client.authentication.list_current_user\nputs response.inspect" + }, + { + "label": "Java", + "lang": "Java", + "source": "import com.scalar.api.client.ScalarApiClient;\nimport com.scalar.api.client.okhttp.ScalarApiOkHttpClient;\nimport com.scalar.api.models.authentication.AuthenticationListCurrentUserParams;\n\nScalarApiClient client = ScalarApiOkHttpClient.builder()\n .bearerAuth(System.getenv(\"BEARER_AUTH\"))\n .build();\n\nvar authentication = client.authentication().listCurrentUser();\nSystem.out.println(authentication);" + }, + { + "lang": "Shell", + "label": "CLI", + "source": "scalarapi authentication list-current-user --bearer-auth \"$BEARER_AUTH\"" + } + ] + } + } + } +} diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..10b2754 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,25 @@ +[project] +name = "scalarApi" +version = "0.1.9" +description = "API for managing Scalar platform resources.\n\n## TypeScript SDK\n\nFor TypeScript, we provide a SDK that makes using our API even easier.\n\n### Install\n\n```bash\nnpm add @scalar/sdk\n```\n\n### Get a Scalar API key\n\nCreate an API key in your Scalar account:\n\n- Dashboard: https://dashboard.scalar.com/account\n- Store it in `.env`, for example:\n\n```bash\nSCALAR_API_KEY=your_personal_token\n```\n\n### Exchange your API key for an access token\n\nThe personal token is not an access token. Exchange it first with `postv1AuthExchange`.\n\nIf you use the personal token directly for authenticated API calls, the API returns `401 Invalid authentication token`.\n\n```ts\nimport { Scalar } from '@scalar/sdk'\n\nconst scalar = new Scalar()\n\nconst exchange = await scalar.auth.postv1AuthExchange({\n personalToken: process.env.SCALAR_API_KEY!,\n})\n\nconst accessToken = exchange.accessToken\n```\n\n### Use the access token\n\nConstruct a second client with bearer auth. Use this authenticated client for API calls.\n\n```ts\nimport { Scalar } from '@scalar/sdk'\n\nconst scalar = new Scalar()\n\nconst exchange = await scalar.auth.postv1AuthExchange({\n personalToken: process.env.SCALAR_API_KEY!,\n})\n\nconst authedScalar = new Scalar({\n bearerAuth: exchange.accessToken,\n})\n```\n\n### Notes\n\n- The exchange request itself can be made from a client constructed with no arguments (`new Scalar()`).\n- The exchanged access token is valid for 12 hours.\n- Timestamps are Unix seconds.\n\n### Read more\n\n- [@scalar/sdk on npm](https://www.npmjs.com/package/@scalar/sdk)" +license = "MIT" +requires-python = ">= 3.9" +dependencies = [ + "httpx>=0.23.0, <1", + "pydantic>=1.9.0, <3", + "typing-extensions>=4.14, <5", + "anyio>=3.5.0, <5", + "distro>=1.7.0, <2", + "sniffio", +] + + +[build-system] +requires = ["hatchling>=1.18.0"] +build-backend = "hatchling.build" + +[tool.hatch.build.targets.wheel] +packages = ["src"] + +[tool.hatch.build.targets.wheel.sources] +"src" = "scalar_api" diff --git a/release-please-config.json b/release-please-config.json new file mode 100644 index 0000000..eb6c26e --- /dev/null +++ b/release-please-config.json @@ -0,0 +1,8 @@ +{ + "packages": { + ".": { + "package-name": "scalarApi", + "release-type": "python" + } + } +} diff --git a/scalar-sdk.manifest.json b/scalar-sdk.manifest.json new file mode 100644 index 0000000..8c10067 --- /dev/null +++ b/scalar-sdk.manifest.json @@ -0,0 +1,9519 @@ +{ + "name": "ScalarApi", + "slug": "scalarApi", + "version": "0.2.0", + "servers": [ + "https://access.scalar.com" + ], + "environments": { + "production": "https://access.scalar.com", + "local": "http://127.0.0.1:4010" + }, + "environmentOrder": [ + "production", + "local" + ], + "auth": [ + "bearer" + ], + "authDetails": [ + { + "kind": "bearer", + "id": "BearerAuth", + "bearerFormat": "JWT" + } + ], + "clientHeaderParams": [], + "schemas": [ + { + "name": "_400", + "source": "_400", + "publicAliases": [], + "deprecated": false, + "type": { + "kind": "object", + "properties": [ + { + "name": "message", + "publicName": "message", + "required": true, + "deprecated": false, + "type": { + "kind": "primitive", + "type": "string" + } + }, + { + "name": "code", + "publicName": "code", + "required": true, + "deprecated": false, + "type": { + "kind": "primitive", + "type": "string" + } + } + ], + "additionalProperties": false + } + }, + { + "name": "_401", + "source": "_401", + "publicAliases": [], + "deprecated": false, + "type": { + "kind": "object", + "properties": [ + { + "name": "message", + "publicName": "message", + "required": true, + "deprecated": false, + "type": { + "kind": "primitive", + "type": "string" + } + }, + { + "name": "code", + "publicName": "code", + "required": true, + "deprecated": false, + "type": { + "kind": "primitive", + "type": "string" + } + } + ], + "additionalProperties": false + } + }, + { + "name": "_403", + "source": "_403", + "publicAliases": [], + "deprecated": false, + "type": { + "kind": "object", + "properties": [ + { + "name": "message", + "publicName": "message", + "required": true, + "deprecated": false, + "type": { + "kind": "primitive", + "type": "string" + } + }, + { + "name": "code", + "publicName": "code", + "required": true, + "deprecated": false, + "type": { + "kind": "primitive", + "type": "string" + } + } + ], + "additionalProperties": false + } + }, + { + "name": "_404", + "source": "_404", + "publicAliases": [], + "deprecated": false, + "type": { + "kind": "object", + "properties": [ + { + "name": "message", + "publicName": "message", + "required": true, + "deprecated": false, + "type": { + "kind": "primitive", + "type": "string" + } + }, + { + "name": "code", + "publicName": "code", + "required": true, + "deprecated": false, + "type": { + "kind": "primitive", + "type": "string" + } + } + ], + "additionalProperties": false + } + }, + { + "name": "_422", + "source": "_422", + "publicAliases": [], + "deprecated": false, + "type": { + "kind": "object", + "properties": [ + { + "name": "message", + "publicName": "message", + "required": true, + "deprecated": false, + "type": { + "kind": "primitive", + "type": "string" + } + }, + { + "name": "code", + "publicName": "code", + "required": true, + "deprecated": false, + "type": { + "kind": "primitive", + "type": "string" + } + } + ], + "additionalProperties": false + } + }, + { + "name": "_500", + "source": "_500", + "publicAliases": [], + "deprecated": false, + "type": { + "kind": "object", + "properties": [ + { + "name": "message", + "publicName": "message", + "required": true, + "deprecated": false, + "type": { + "kind": "primitive", + "type": "string" + } + }, + { + "name": "code", + "publicName": "code", + "required": true, + "deprecated": false, + "type": { + "kind": "primitive", + "type": "string" + } + } + ], + "additionalProperties": false + } + }, + { + "name": "ApiDocument", + "source": "ApiDocument", + "publicAliases": [], + "deprecated": false, + "type": { + "kind": "object", + "properties": [ + { + "name": "uid", + "publicName": "uid", + "required": true, + "deprecated": false, + "type": { + "kind": "ref", + "name": "Nanoid" + } + }, + { + "name": "version", + "publicName": "version", + "required": true, + "deprecated": false, + "type": { + "kind": "ref", + "name": "Version" + } + }, + { + "name": "title", + "publicName": "title", + "required": true, + "deprecated": false, + "type": { + "kind": "primitive", + "type": "string", + "validation": { + "maxLength": 100 + } + } + }, + { + "name": "slug", + "publicName": "slug", + "required": true, + "deprecated": false, + "type": { + "kind": "ref", + "name": "Slug" + } + }, + { + "name": "description", + "publicName": "description", + "required": true, + "deprecated": false, + "type": { + "kind": "primitive", + "type": "string" + } + }, + { + "name": "namespace", + "publicName": "namespace", + "required": true, + "deprecated": false, + "type": { + "kind": "ref", + "name": "Namespace" + } + }, + { + "name": "isPrivate", + "publicName": "isPrivate", + "required": true, + "deprecated": false, + "type": { + "kind": "primitive", + "type": "boolean" + } + }, + { + "name": "tags", + "publicName": "tags", + "required": true, + "deprecated": false, + "type": { + "kind": "primitive", + "type": "string" + } + }, + { + "name": "versions", + "publicName": "versions", + "required": true, + "deprecated": false, + "type": { + "kind": "array", + "items": { + "kind": "ref", + "name": "ManagedDocVersion" + } + } + } + ], + "additionalProperties": false + } + }, + { + "name": "Nanoid", + "source": "Nanoid", + "publicAliases": [], + "deprecated": false, + "type": { + "kind": "primitive", + "type": "string", + "validation": { + "minLength": 5 + } + } + }, + { + "name": "Version", + "source": "Version", + "publicAliases": [], + "deprecated": false, + "type": { + "kind": "primitive", + "type": "string", + "validation": { + "minLength": 1 + } + } + }, + { + "name": "Slug", + "source": "Slug", + "publicAliases": [], + "deprecated": false, + "type": { + "kind": "primitive", + "type": "string", + "validation": { + "pattern": "^[a-z](?:[a-z0-9-]*[a-z0-9])?$", + "minLength": 3, + "maxLength": 60 + } + } + }, + { + "name": "Namespace", + "source": "Namespace", + "publicAliases": [], + "deprecated": false, + "type": { + "kind": "primitive", + "type": "string", + "validation": { + "pattern": "^[a-zA-Z0-9-_]+$", + "minLength": 3, + "maxLength": 50 + } + } + }, + { + "name": "ManagedDocVersion", + "source": "ManagedDocVersion", + "publicAliases": [], + "deprecated": false, + "type": { + "kind": "object", + "properties": [ + { + "name": "uid", + "publicName": "uid", + "required": true, + "deprecated": false, + "type": { + "kind": "ref", + "name": "Nanoid" + } + }, + { + "name": "createdAt", + "publicName": "createdAt", + "required": true, + "deprecated": false, + "type": { + "kind": "primitive", + "type": "number" + } + }, + { + "name": "version", + "publicName": "version", + "required": true, + "deprecated": false, + "type": { + "kind": "ref", + "name": "Version" + } + }, + { + "name": "upgraded", + "publicName": "upgraded", + "required": true, + "deprecated": false, + "type": { + "kind": "primitive", + "type": "boolean" + } + }, + { + "name": "embedStatus", + "publicName": "embedStatus", + "required": true, + "deprecated": false, + "type": { + "kind": "union", + "variants": [ + { + "kind": "enum", + "values": [ + "complete", + "failed" + ], + "names": [ + "Complete", + "Failed" + ], + "deprecations": [ + false, + false + ] + }, + { + "kind": "null" + } + ] + } + }, + { + "name": "tags", + "publicName": "tags", + "required": true, + "deprecated": false, + "type": { + "kind": "array", + "items": { + "kind": "primitive", + "type": "string" + } + } + }, + { + "name": "tools", + "publicName": "tools", + "required": false, + "deprecated": false, + "type": { + "kind": "array", + "items": { + "kind": "object", + "properties": [ + { + "name": "path", + "publicName": "path", + "required": true, + "deprecated": false, + "type": { + "kind": "primitive", + "type": "string" + } + }, + { + "name": "method", + "publicName": "method", + "required": true, + "deprecated": false, + "type": { + "kind": "ref", + "name": "Method" + } + }, + { + "name": "enabledTools", + "publicName": "enabledTools", + "required": true, + "deprecated": false, + "type": { + "kind": "array", + "items": { + "kind": "enum", + "values": [ + "execute-request", + "get-mini-openapi-spec" + ], + "names": [ + "ExecuteRequest", + "GetMiniOpenapiSpec" + ], + "deprecations": [ + false, + false + ] + } + } + } + ], + "additionalProperties": false + } + } + }, + { + "name": "yamlSha", + "publicName": "yamlSha", + "required": false, + "deprecated": false, + "type": { + "kind": "primitive", + "type": "string" + } + }, + { + "name": "jsonSha", + "publicName": "jsonSha", + "required": false, + "deprecated": false, + "type": { + "kind": "primitive", + "type": "string" + } + }, + { + "name": "versionSha", + "publicName": "versionSha", + "required": false, + "deprecated": false, + "type": { + "kind": "primitive", + "type": "string" + } + } + ], + "additionalProperties": false + } + }, + { + "name": "Method", + "source": "Method", + "publicAliases": [], + "deprecated": false, + "type": { + "kind": "enum", + "values": [ + "delete", + "get", + "head", + "options", + "patch", + "post", + "put", + "trace" + ], + "names": [ + "Delete", + "Get", + "Head", + "Options", + "Patch", + "Post", + "Put", + "Trace" + ], + "deprecations": [ + false, + false, + false, + false, + false, + false, + false, + false + ] + } + }, + { + "name": "AccessGroup", + "source": "AccessGroup", + "publicAliases": [], + "deprecated": false, + "type": { + "kind": "object", + "properties": [ + { + "name": "accessGroupSlug", + "publicName": "accessGroupSlug", + "required": true, + "deprecated": false, + "type": { + "kind": "ref", + "name": "Slug" + } + } + ], + "additionalProperties": false + } + }, + { + "name": "Schema", + "source": "Schema", + "publicAliases": [], + "deprecated": false, + "type": { + "kind": "object", + "properties": [ + { + "name": "uid", + "publicName": "uid", + "required": true, + "deprecated": false, + "type": { + "kind": "ref", + "name": "Nanoid" + } + }, + { + "name": "title", + "publicName": "title", + "required": true, + "deprecated": false, + "type": { + "kind": "primitive", + "type": "string", + "validation": { + "maxLength": 100 + } + } + }, + { + "name": "description", + "publicName": "description", + "required": true, + "deprecated": false, + "type": { + "kind": "primitive", + "type": "string" + } + }, + { + "name": "slug", + "publicName": "slug", + "required": true, + "deprecated": false, + "type": { + "kind": "ref", + "name": "Slug" + } + }, + { + "name": "namespace", + "publicName": "namespace", + "required": true, + "deprecated": false, + "type": { + "kind": "ref", + "name": "Namespace" + } + }, + { + "name": "isPrivate", + "publicName": "isPrivate", + "required": true, + "deprecated": false, + "type": { + "kind": "primitive", + "type": "boolean" + } + }, + { + "name": "versions", + "publicName": "versions", + "required": true, + "deprecated": false, + "type": { + "kind": "array", + "items": { + "kind": "ref", + "name": "ManagedSchemaVersion" + } + } + } + ], + "additionalProperties": false + } + }, + { + "name": "ManagedSchemaVersion", + "source": "ManagedSchemaVersion", + "publicAliases": [], + "deprecated": false, + "type": { + "kind": "object", + "properties": [ + { + "name": "uid", + "publicName": "uid", + "required": true, + "deprecated": false, + "type": { + "kind": "ref", + "name": "Nanoid" + } + }, + { + "name": "createdAt", + "publicName": "createdAt", + "required": true, + "deprecated": false, + "type": { + "kind": "ref", + "name": "Timestamp" + } + }, + { + "name": "updatedAt", + "publicName": "updatedAt", + "required": true, + "deprecated": false, + "type": { + "kind": "ref", + "name": "Timestamp" + } + }, + { + "name": "version", + "publicName": "version", + "required": true, + "deprecated": false, + "type": { + "kind": "ref", + "name": "Version" + } + } + ], + "additionalProperties": false + } + }, + { + "name": "Timestamp", + "source": "Timestamp", + "publicAliases": [], + "deprecated": false, + "type": { + "kind": "primitive", + "type": "integer", + "validation": {} + } + }, + { + "name": "Uid", + "source": "Uid", + "publicAliases": [], + "deprecated": false, + "type": { + "kind": "object", + "properties": [ + { + "name": "uid", + "publicName": "uid", + "required": true, + "deprecated": false, + "type": { + "kind": "ref", + "name": "Nanoid" + } + } + ], + "additionalProperties": false + } + }, + { + "name": "LoginPortalEmail", + "source": "LoginPortalEmail", + "publicAliases": [], + "deprecated": false, + "type": { + "kind": "object", + "properties": [ + { + "name": "logo", + "publicName": "logo", + "required": true, + "deprecated": false, + "type": { + "kind": "primitive", + "type": "string" + } + }, + { + "name": "logoSize", + "publicName": "logoSize", + "required": true, + "deprecated": false, + "type": { + "kind": "primitive", + "type": "string" + } + }, + { + "name": "buttonText", + "publicName": "buttonText", + "required": true, + "deprecated": false, + "type": { + "kind": "primitive", + "type": "string", + "validation": { + "maxLength": 50 + } + } + }, + { + "name": "message", + "publicName": "message", + "required": true, + "deprecated": false, + "type": { + "kind": "primitive", + "type": "string", + "validation": { + "maxLength": 1000 + } + } + }, + { + "name": "title", + "publicName": "title", + "required": true, + "deprecated": false, + "type": { + "kind": "primitive", + "type": "string", + "validation": { + "maxLength": 100 + } + } + }, + { + "name": "mainColor", + "publicName": "mainColor", + "required": true, + "deprecated": false, + "type": { + "kind": "primitive", + "type": "string", + "validation": { + "maxLength": 100 + } + } + }, + { + "name": "mainBackground", + "publicName": "mainBackground", + "required": true, + "deprecated": false, + "type": { + "kind": "primitive", + "type": "string", + "validation": { + "maxLength": 100 + } + } + }, + { + "name": "cardColor", + "publicName": "cardColor", + "required": true, + "deprecated": false, + "type": { + "kind": "primitive", + "type": "string", + "validation": { + "maxLength": 100 + } + } + }, + { + "name": "cardBackground", + "publicName": "cardBackground", + "required": true, + "deprecated": false, + "type": { + "kind": "primitive", + "type": "string", + "validation": { + "maxLength": 100 + } + } + }, + { + "name": "buttonColor", + "publicName": "buttonColor", + "required": true, + "deprecated": false, + "type": { + "kind": "primitive", + "type": "string", + "validation": { + "maxLength": 100 + } + } + }, + { + "name": "buttonBackground", + "publicName": "buttonBackground", + "required": true, + "deprecated": false, + "type": { + "kind": "primitive", + "type": "string", + "validation": { + "maxLength": 100 + } + } + } + ], + "additionalProperties": false + } + }, + { + "name": "LoginPortalPage", + "source": "LoginPortalPage", + "publicAliases": [], + "deprecated": false, + "type": { + "kind": "object", + "properties": [ + { + "name": "title", + "publicName": "title", + "required": true, + "deprecated": false, + "type": { + "kind": "primitive", + "type": "string", + "validation": { + "maxLength": 100 + } + } + }, + { + "name": "description", + "publicName": "description", + "required": true, + "deprecated": false, + "type": { + "kind": "primitive", + "type": "string", + "validation": { + "maxLength": 500 + } + } + }, + { + "name": "head", + "publicName": "head", + "required": true, + "deprecated": false, + "type": { + "kind": "primitive", + "type": "string" + } + }, + { + "name": "script", + "publicName": "script", + "required": true, + "deprecated": false, + "type": { + "kind": "primitive", + "type": "string" + } + }, + { + "name": "theme", + "publicName": "theme", + "required": true, + "deprecated": false, + "type": { + "kind": "primitive", + "type": "string" + } + }, + { + "name": "companyName", + "publicName": "companyName", + "required": true, + "deprecated": false, + "type": { + "kind": "primitive", + "type": "string", + "validation": { + "maxLength": 100 + } + } + }, + { + "name": "logo", + "publicName": "logo", + "required": true, + "deprecated": false, + "type": { + "kind": "primitive", + "type": "string" + } + }, + { + "name": "logoURL", + "publicName": "logoURL", + "required": true, + "deprecated": false, + "type": { + "kind": "primitive", + "type": "string" + } + }, + { + "name": "favicon", + "publicName": "favicon", + "required": true, + "deprecated": false, + "type": { + "kind": "primitive", + "type": "string" + } + }, + { + "name": "termsLink", + "publicName": "termsLink", + "required": true, + "deprecated": false, + "type": { + "kind": "primitive", + "type": "string" + } + }, + { + "name": "privacyLink", + "publicName": "privacyLink", + "required": true, + "deprecated": false, + "type": { + "kind": "primitive", + "type": "string" + } + }, + { + "name": "formTitle", + "publicName": "formTitle", + "required": true, + "deprecated": false, + "type": { + "kind": "primitive", + "type": "string", + "validation": { + "maxLength": 100 + } + } + }, + { + "name": "formDescription", + "publicName": "formDescription", + "required": true, + "deprecated": false, + "type": { + "kind": "primitive", + "type": "string", + "validation": { + "maxLength": 500 + } + } + }, + { + "name": "formImage", + "publicName": "formImage", + "required": true, + "deprecated": false, + "type": { + "kind": "primitive", + "type": "string" + } + } + ], + "additionalProperties": false + } + }, + { + "name": "LoginPortal", + "source": "LoginPortal", + "publicAliases": [], + "deprecated": false, + "type": { + "kind": "object", + "properties": [ + { + "name": "uid", + "publicName": "uid", + "required": true, + "deprecated": false, + "type": { + "kind": "ref", + "name": "Nanoid" + } + }, + { + "name": "title", + "publicName": "title", + "required": true, + "deprecated": false, + "type": { + "kind": "primitive", + "type": "string", + "validation": { + "maxLength": 200 + } + } + }, + { + "name": "slug", + "publicName": "slug", + "required": true, + "deprecated": false, + "type": { + "kind": "ref", + "name": "Slug" + } + } + ], + "additionalProperties": false + } + }, + { + "name": "Rule", + "source": "Rule", + "publicAliases": [], + "deprecated": false, + "type": { + "kind": "object", + "properties": [ + { + "name": "uid", + "publicName": "uid", + "required": true, + "deprecated": false, + "type": { + "kind": "ref", + "name": "Nanoid" + } + }, + { + "name": "title", + "publicName": "title", + "required": true, + "deprecated": false, + "type": { + "kind": "primitive", + "type": "string", + "validation": { + "maxLength": 100 + } + } + }, + { + "name": "description", + "publicName": "description", + "required": true, + "deprecated": false, + "type": { + "kind": "primitive", + "type": "string" + } + }, + { + "name": "slug", + "publicName": "slug", + "required": true, + "deprecated": false, + "type": { + "kind": "ref", + "name": "Slug" + } + }, + { + "name": "namespace", + "publicName": "namespace", + "required": true, + "deprecated": false, + "type": { + "kind": "ref", + "name": "Namespace" + } + }, + { + "name": "isPrivate", + "publicName": "isPrivate", + "required": true, + "deprecated": false, + "type": { + "kind": "primitive", + "type": "boolean" + } + } + ], + "additionalProperties": false + } + }, + { + "name": "Theme", + "source": "Theme", + "publicAliases": [], + "deprecated": false, + "type": { + "kind": "object", + "properties": [ + { + "name": "uid", + "publicName": "uid", + "required": true, + "deprecated": false, + "type": { + "kind": "ref", + "name": "Nanoid" + } + }, + { + "name": "name", + "publicName": "name", + "required": true, + "deprecated": false, + "type": { + "kind": "primitive", + "type": "string" + } + }, + { + "name": "description", + "publicName": "description", + "required": true, + "deprecated": false, + "type": { + "kind": "primitive", + "type": "string" + } + }, + { + "name": "slug", + "publicName": "slug", + "required": true, + "deprecated": false, + "type": { + "kind": "ref", + "name": "Slug" + } + } + ], + "additionalProperties": false + } + }, + { + "name": "Team", + "source": "Team", + "publicAliases": [], + "deprecated": false, + "type": { + "kind": "object", + "properties": [ + { + "name": "uid", + "publicName": "uid", + "required": true, + "deprecated": false, + "type": { + "kind": "ref", + "name": "Nanoid" + } + }, + { + "name": "name", + "publicName": "name", + "required": true, + "deprecated": false, + "type": { + "kind": "ref", + "name": "TeamName" + } + }, + { + "name": "imageUri", + "publicName": "imageUri", + "required": false, + "deprecated": false, + "type": { + "kind": "ref", + "name": "TeamImage" + } + }, + { + "name": "slug", + "publicName": "slug", + "required": true, + "deprecated": false, + "type": { + "kind": "ref", + "name": "Slug" + } + }, + { + "name": "theme", + "publicName": "theme", + "required": true, + "deprecated": false, + "type": { + "kind": "primitive", + "type": "string" + } + } + ], + "additionalProperties": false + } + }, + { + "name": "TeamName", + "source": "TeamName", + "publicAliases": [], + "deprecated": false, + "type": { + "kind": "primitive", + "type": "string" + } + }, + { + "name": "TeamImage", + "source": "TeamImage", + "publicAliases": [], + "deprecated": false, + "type": { + "kind": "primitive", + "type": "string" + } + }, + { + "name": "GithubProject", + "source": "GithubProject", + "publicAliases": [], + "deprecated": false, + "type": { + "kind": "object", + "properties": [ + { + "name": "uid", + "publicName": "uid", + "required": true, + "deprecated": false, + "type": { + "kind": "ref", + "name": "Nanoid" + } + }, + { + "name": "createdAt", + "publicName": "createdAt", + "required": true, + "deprecated": false, + "type": { + "kind": "ref", + "name": "Timestamp" + } + }, + { + "name": "updatedAt", + "publicName": "updatedAt", + "required": true, + "deprecated": false, + "type": { + "kind": "ref", + "name": "Timestamp" + } + }, + { + "name": "name", + "publicName": "name", + "required": true, + "deprecated": false, + "type": { + "kind": "primitive", + "type": "string" + } + }, + { + "name": "activeDeployment", + "publicName": "activeDeployment", + "required": true, + "deprecated": false, + "type": { + "kind": "union", + "variants": [ + { + "kind": "ref", + "name": "ActiveDeployment" + }, + { + "kind": "null" + } + ] + } + }, + { + "name": "lastPublished", + "publicName": "lastPublished", + "required": true, + "deprecated": false, + "type": { + "kind": "union", + "variants": [ + { + "kind": "ref", + "name": "Timestamp" + }, + { + "kind": "null" + } + ] + } + }, + { + "name": "lastPublishedUid", + "publicName": "lastPublishedUid", + "required": true, + "deprecated": false, + "type": { + "kind": "union", + "variants": [ + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "null" + } + ] + } + }, + { + "name": "loginPortalUid", + "publicName": "loginPortalUid", + "required": true, + "deprecated": false, + "type": { + "kind": "primitive", + "type": "string" + } + }, + { + "name": "activeThemeId", + "publicName": "activeThemeId", + "required": true, + "deprecated": false, + "type": { + "kind": "primitive", + "type": "string" + } + }, + { + "name": "typesenseId", + "publicName": "typesenseId", + "required": false, + "deprecated": false, + "type": { + "kind": "primitive", + "type": "number" + } + }, + { + "name": "isPrivate", + "publicName": "isPrivate", + "required": true, + "deprecated": false, + "type": { + "kind": "primitive", + "type": "boolean" + } + }, + { + "name": "agentEnabled", + "publicName": "agentEnabled", + "required": true, + "deprecated": false, + "type": { + "kind": "primitive", + "type": "boolean" + } + }, + { + "name": "accessGroups", + "publicName": "accessGroups", + "required": true, + "deprecated": false, + "type": { + "kind": "primitive", + "type": "string" + } + }, + { + "name": "slug", + "publicName": "slug", + "required": true, + "deprecated": false, + "type": { + "kind": "ref", + "name": "Slug" + } + }, + { + "name": "publishStatus", + "publicName": "publishStatus", + "required": true, + "deprecated": false, + "type": { + "kind": "primitive", + "type": "string" + } + }, + { + "name": "publishMessage", + "publicName": "publishMessage", + "required": true, + "deprecated": false, + "type": { + "kind": "primitive", + "type": "string" + } + }, + { + "name": "repository", + "publicName": "repository", + "required": false, + "deprecated": false, + "type": { + "kind": "union", + "variants": [ + { + "kind": "ref", + "name": "GithubProjectRepository" + }, + { + "kind": "null" + } + ] + } + } + ], + "additionalProperties": false + } + }, + { + "name": "ActiveDeployment", + "source": "ActiveDeployment", + "publicAliases": [], + "deprecated": false, + "type": { + "kind": "object", + "properties": [ + { + "name": "uid", + "publicName": "uid", + "required": true, + "deprecated": false, + "type": { + "kind": "primitive", + "type": "string" + } + }, + { + "name": "domain", + "publicName": "domain", + "required": true, + "deprecated": false, + "type": { + "kind": "primitive", + "type": "string" + } + }, + { + "name": "publishedAt", + "publicName": "publishedAt", + "required": true, + "deprecated": false, + "type": { + "kind": "ref", + "name": "Timestamp" + } + } + ], + "additionalProperties": false + } + }, + { + "name": "GithubProjectRepository", + "source": "GithubProjectRepository", + "publicAliases": [], + "deprecated": false, + "type": { + "kind": "object", + "properties": [ + { + "name": "linkedBy", + "publicName": "linkedBy", + "required": true, + "deprecated": false, + "type": { + "kind": "primitive", + "type": "string" + } + }, + { + "name": "id", + "publicName": "id", + "required": true, + "deprecated": false, + "type": { + "kind": "primitive", + "type": "number" + } + }, + { + "name": "name", + "publicName": "name", + "required": true, + "deprecated": false, + "type": { + "kind": "primitive", + "type": "string", + "validation": { + "minLength": 2 + } + } + }, + { + "name": "configPath", + "publicName": "configPath", + "required": true, + "deprecated": false, + "type": { + "kind": "primitive", + "type": "string" + } + }, + { + "name": "branch", + "publicName": "branch", + "required": true, + "deprecated": false, + "type": { + "kind": "primitive", + "type": "string" + } + }, + { + "name": "publishOnMerge", + "publicName": "publishOnMerge", + "required": true, + "deprecated": false, + "type": { + "kind": "primitive", + "type": "boolean" + } + }, + { + "name": "publishPreviews", + "publicName": "publishPreviews", + "required": true, + "deprecated": false, + "type": { + "kind": "primitive", + "type": "boolean" + } + }, + { + "name": "prComments", + "publicName": "prComments", + "required": true, + "deprecated": false, + "type": { + "kind": "primitive", + "type": "boolean" + } + }, + { + "name": "expired", + "publicName": "expired", + "required": true, + "deprecated": false, + "type": { + "kind": "primitive", + "type": "boolean" + } + } + ], + "additionalProperties": false + } + }, + { + "name": "Email", + "source": "Email", + "publicAliases": [], + "deprecated": false, + "type": { + "kind": "primitive", + "type": "string", + "format": "email", + "validation": { + "pattern": "^(?!\\.)(?!.*\\.\\.)([A-Za-z0-9_'+\\-\\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$" + } + } + }, + { + "name": "TeamSummary", + "source": "TeamSummary", + "publicAliases": [], + "deprecated": false, + "type": { + "kind": "object", + "properties": [ + { + "name": "uid", + "publicName": "uid", + "required": true, + "deprecated": false, + "type": { + "kind": "ref", + "name": "Nanoid" + } + }, + { + "name": "name", + "publicName": "name", + "required": true, + "deprecated": false, + "type": { + "kind": "ref", + "name": "TeamName" + } + }, + { + "name": "imageUri", + "publicName": "imageUri", + "required": false, + "deprecated": false, + "type": { + "kind": "ref", + "name": "TeamImage" + } + } + ], + "additionalProperties": false + } + }, + { + "name": "User", + "source": "User", + "publicAliases": [], + "deprecated": false, + "type": { + "kind": "object", + "properties": [ + { + "name": "uid", + "publicName": "uid", + "required": true, + "deprecated": false, + "type": { + "kind": "ref", + "name": "Nanoid" + } + }, + { + "name": "createdAt", + "publicName": "createdAt", + "required": true, + "deprecated": false, + "type": { + "kind": "ref", + "name": "Timestamp" + } + }, + { + "name": "updatedAt", + "publicName": "updatedAt", + "required": true, + "deprecated": false, + "type": { + "kind": "ref", + "name": "Timestamp" + } + }, + { + "name": "email", + "publicName": "email", + "required": true, + "deprecated": false, + "type": { + "kind": "ref", + "name": "Email" + } + }, + { + "name": "theme", + "publicName": "theme", + "required": false, + "deprecated": false, + "type": { + "kind": "primitive", + "type": "string" + } + }, + { + "name": "activeTeamId", + "publicName": "activeTeamId", + "required": true, + "deprecated": false, + "type": { + "kind": "union", + "variants": [ + { + "kind": "primitive", + "type": "string" + }, + { + "kind": "null" + } + ] + } + }, + { + "name": "hasGithub", + "publicName": "hasGithub", + "required": true, + "deprecated": false, + "type": { + "kind": "primitive", + "type": "boolean" + } + }, + { + "name": "teams", + "publicName": "teams", + "required": true, + "deprecated": false, + "type": { + "kind": "array", + "items": { + "kind": "ref", + "name": "TeamSummary" + } + } + } + ], + "additionalProperties": false + } + } + ], + "resources": [ + "registry", + "schemas", + "schemas.version", + "schemas.accessGroup", + "loginPortals", + "rules", + "themes", + "teams", + "scalarDocs", + "namespaces", + "authentication" + ], + "publicResources": [ + "registry", + "schemas", + "schemas.version", + "schemas.accessGroup", + "loginPortals", + "rules", + "themes", + "teams", + "scalarDocs", + "namespaces", + "authentication" + ], + "operations": [ + { + "resource": "registry", + "publicResource": "registry", + "operation": "listAllApiDocuments", + "publicOperation": "listAllApiDocuments", + "deprecated": false, + "method": "GET", + "path": "/v1/apis", + "pathParams": [], + "publicPathParams": [], + "queryParams": [], + "publicQueryParams": [], + "headerParams": [], + "publicHeaderParams": [], + "bodyParams": [], + "publicBodyParams": [], + "pathParamDetails": [], + "queryParamDetails": [], + "headerParamDetails": [], + "cookieParams": [], + "publicCookieParams": [], + "cookieParamDetails": [], + "response": { + "status": "200", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ] + }, + "result": { + "successStatus": "200", + "errorStatuses": [ + "400", + "401", + "403", + "404", + "422", + "500" + ] + }, + "errorResponses": [ + { + "status": "400", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_400", + "publicAliases": [] + } + }, + { + "status": "401", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_401", + "publicAliases": [] + } + }, + { + "status": "403", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_403", + "publicAliases": [] + } + }, + { + "status": "404", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_404", + "publicAliases": [] + } + }, + { + "status": "422", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_422", + "publicAliases": [] + } + }, + { + "status": "500", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_500", + "publicAliases": [] + } + } + ], + "responseLinks": [], + "transport": "http" + }, + { + "resource": "registry", + "publicResource": "registry", + "operation": "listApiDocuments", + "publicOperation": "listApiDocuments", + "deprecated": false, + "method": "GET", + "path": "/v1/apis/{namespace}", + "pathParams": [ + "namespace" + ], + "publicPathParams": [ + "namespace" + ], + "queryParams": [], + "publicQueryParams": [], + "headerParams": [], + "publicHeaderParams": [], + "bodyParams": [], + "publicBodyParams": [], + "pathParamDetails": [ + { + "name": "namespace", + "required": true, + "style": "simple", + "explode": false + } + ], + "queryParamDetails": [], + "headerParamDetails": [], + "cookieParams": [], + "publicCookieParams": [], + "cookieParamDetails": [], + "paramsModel": { + "publicName": "RegistryListApiDocumentsParams" + }, + "response": { + "status": "200", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ] + }, + "result": { + "successStatus": "200", + "errorStatuses": [ + "400", + "401", + "403", + "404", + "422", + "500" + ] + }, + "errorResponses": [ + { + "status": "400", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_400", + "publicAliases": [] + } + }, + { + "status": "401", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_401", + "publicAliases": [] + } + }, + { + "status": "403", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_403", + "publicAliases": [] + } + }, + { + "status": "404", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_404", + "publicAliases": [] + } + }, + { + "status": "422", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_422", + "publicAliases": [] + } + }, + { + "status": "500", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_500", + "publicAliases": [] + } + } + ], + "responseLinks": [], + "transport": "http" + }, + { + "resource": "registry", + "publicResource": "registry", + "operation": "createApiDocument", + "publicOperation": "createApiDocument", + "deprecated": false, + "method": "POST", + "path": "/v1/apis/{namespace}", + "pathParams": [ + "namespace" + ], + "publicPathParams": [ + "namespace" + ], + "queryParams": [], + "publicQueryParams": [], + "headerParams": [], + "publicHeaderParams": [], + "bodyParams": [ + "title", + "description", + "version", + "slug", + "ruleset", + "isPrivate", + "document" + ], + "publicBodyParams": [ + "title", + "description", + "version", + "slug", + "ruleset", + "isPrivate", + "document" + ], + "pathParamDetails": [ + { + "name": "namespace", + "required": true, + "style": "simple", + "explode": false + } + ], + "queryParamDetails": [], + "headerParamDetails": [], + "cookieParams": [], + "publicCookieParams": [], + "cookieParamDetails": [], + "paramsModel": { + "publicName": "RegistryCreateApiDocumentParams" + }, + "requestBody": { + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "required": true, + "publicName": "body", + "publicIdentifier": "body" + }, + "response": { + "status": "200", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ] + }, + "result": { + "successStatus": "200", + "errorStatuses": [ + "400", + "401", + "403", + "404", + "422", + "500" + ] + }, + "errorResponses": [ + { + "status": "400", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_400", + "publicAliases": [] + } + }, + { + "status": "401", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_401", + "publicAliases": [] + } + }, + { + "status": "403", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_403", + "publicAliases": [] + } + }, + { + "status": "404", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_404", + "publicAliases": [] + } + }, + { + "status": "422", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_422", + "publicAliases": [] + } + }, + { + "status": "500", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_500", + "publicAliases": [] + } + } + ], + "responseLinks": [], + "transport": "http" + }, + { + "resource": "registry", + "publicResource": "registry", + "operation": "updateApiDocument", + "publicOperation": "updateApiDocument", + "deprecated": false, + "method": "PATCH", + "path": "/v1/apis/{namespace}/{slug}", + "pathParams": [ + "namespace", + "slug" + ], + "publicPathParams": [ + "namespace", + "slug" + ], + "queryParams": [], + "publicQueryParams": [], + "headerParams": [], + "publicHeaderParams": [], + "bodyParams": [ + "title", + "description", + "isPrivate", + "ruleset" + ], + "publicBodyParams": [ + "title", + "description", + "isPrivate", + "ruleset" + ], + "pathParamDetails": [ + { + "name": "namespace", + "required": true, + "style": "simple", + "explode": false + }, + { + "name": "slug", + "required": true, + "style": "simple", + "explode": false + } + ], + "queryParamDetails": [], + "headerParamDetails": [], + "cookieParams": [], + "publicCookieParams": [], + "cookieParamDetails": [], + "paramsModel": { + "publicName": "RegistryUpdateApiDocumentParams" + }, + "requestBody": { + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "required": true, + "publicName": "body", + "publicIdentifier": "body" + }, + "response": { + "status": "200", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ] + }, + "result": { + "successStatus": "200", + "errorStatuses": [ + "400", + "401", + "403", + "404", + "422", + "500" + ] + }, + "errorResponses": [ + { + "status": "400", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_400", + "publicAliases": [] + } + }, + { + "status": "401", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_401", + "publicAliases": [] + } + }, + { + "status": "403", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_403", + "publicAliases": [] + } + }, + { + "status": "404", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_404", + "publicAliases": [] + } + }, + { + "status": "422", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_422", + "publicAliases": [] + } + }, + { + "status": "500", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_500", + "publicAliases": [] + } + } + ], + "responseLinks": [], + "transport": "http" + }, + { + "resource": "registry", + "publicResource": "registry", + "operation": "deleteApiDocument", + "publicOperation": "deleteApiDocument", + "deprecated": false, + "method": "DELETE", + "path": "/v1/apis/{namespace}/{slug}", + "pathParams": [ + "namespace", + "slug" + ], + "publicPathParams": [ + "namespace", + "slug" + ], + "queryParams": [], + "publicQueryParams": [], + "headerParams": [], + "publicHeaderParams": [], + "bodyParams": [], + "publicBodyParams": [], + "pathParamDetails": [ + { + "name": "namespace", + "required": true, + "style": "simple", + "explode": false + }, + { + "name": "slug", + "required": true, + "style": "simple", + "explode": false + } + ], + "queryParamDetails": [], + "headerParamDetails": [], + "cookieParams": [], + "publicCookieParams": [], + "cookieParamDetails": [], + "paramsModel": { + "publicName": "RegistryDeleteApiDocumentParams" + }, + "response": { + "status": "200", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ] + }, + "result": { + "successStatus": "200", + "errorStatuses": [ + "400", + "401", + "403", + "404", + "422", + "500" + ] + }, + "errorResponses": [ + { + "status": "400", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_400", + "publicAliases": [] + } + }, + { + "status": "401", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_401", + "publicAliases": [] + } + }, + { + "status": "403", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_403", + "publicAliases": [] + } + }, + { + "status": "404", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_404", + "publicAliases": [] + } + }, + { + "status": "422", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_422", + "publicAliases": [] + } + }, + { + "status": "500", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_500", + "publicAliases": [] + } + } + ], + "responseLinks": [], + "transport": "http" + }, + { + "resource": "registry", + "publicResource": "registry", + "operation": "retrieveApiDocumentVersion", + "publicOperation": "retrieveApiDocumentVersion", + "deprecated": false, + "method": "GET", + "path": "/v1/apis/{namespace}/{slug}/version/{semver}", + "pathParams": [ + "namespace", + "slug", + "semver" + ], + "publicPathParams": [ + "namespace", + "slug", + "semver" + ], + "queryParams": [], + "publicQueryParams": [], + "headerParams": [], + "publicHeaderParams": [], + "bodyParams": [], + "publicBodyParams": [], + "pathParamDetails": [ + { + "name": "namespace", + "required": true, + "style": "simple", + "explode": false + }, + { + "name": "slug", + "required": true, + "style": "simple", + "explode": false + }, + { + "name": "semver", + "required": true, + "style": "simple", + "explode": false + } + ], + "queryParamDetails": [], + "headerParamDetails": [], + "cookieParams": [], + "publicCookieParams": [], + "cookieParamDetails": [], + "paramsModel": { + "publicName": "RegistryRetrieveApiDocumentVersionParams" + }, + "response": { + "status": "200", + "contentType": "text/plain", + "encoding": "text", + "contents": [ + { + "contentType": "text/plain", + "encoding": "text" + } + ] + }, + "result": { + "successStatus": "200", + "errorStatuses": [ + "400", + "401", + "403", + "404", + "422", + "500" + ] + }, + "errorResponses": [ + { + "status": "400", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_400", + "publicAliases": [] + } + }, + { + "status": "401", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_401", + "publicAliases": [] + } + }, + { + "status": "403", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_403", + "publicAliases": [] + } + }, + { + "status": "404", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_404", + "publicAliases": [] + } + }, + { + "status": "422", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_422", + "publicAliases": [] + } + }, + { + "status": "500", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_500", + "publicAliases": [] + } + } + ], + "responseLinks": [], + "transport": "http" + }, + { + "resource": "registry", + "publicResource": "registry", + "operation": "updateApiDocumentVersion", + "publicOperation": "updateApiDocumentVersion", + "deprecated": false, + "method": "PATCH", + "path": "/v1/apis/{namespace}/{slug}/version/{semver}", + "pathParams": [ + "namespace", + "slug", + "semver" + ], + "publicPathParams": [ + "namespace", + "slug", + "semver" + ], + "queryParams": [], + "publicQueryParams": [], + "headerParams": [], + "publicHeaderParams": [], + "bodyParams": [ + "document", + "lastKnownVersionSha" + ], + "publicBodyParams": [ + "document", + "lastKnownVersionSha" + ], + "pathParamDetails": [ + { + "name": "namespace", + "required": true, + "style": "simple", + "explode": false + }, + { + "name": "slug", + "required": true, + "style": "simple", + "explode": false + }, + { + "name": "semver", + "required": true, + "style": "simple", + "explode": false + } + ], + "queryParamDetails": [], + "headerParamDetails": [], + "cookieParams": [], + "publicCookieParams": [], + "cookieParamDetails": [], + "paramsModel": { + "publicName": "RegistryUpdateApiDocumentVersionParams" + }, + "requestBody": { + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "required": true, + "publicName": "body", + "publicIdentifier": "body" + }, + "response": { + "status": "200", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ] + }, + "result": { + "successStatus": "200", + "errorStatuses": [ + "400", + "401", + "403", + "404", + "422", + "500" + ] + }, + "errorResponses": [ + { + "status": "400", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_400", + "publicAliases": [] + } + }, + { + "status": "401", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_401", + "publicAliases": [] + } + }, + { + "status": "403", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_403", + "publicAliases": [] + } + }, + { + "status": "404", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_404", + "publicAliases": [] + } + }, + { + "status": "422", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_422", + "publicAliases": [] + } + }, + { + "status": "500", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_500", + "publicAliases": [] + } + } + ], + "responseLinks": [], + "transport": "http" + }, + { + "resource": "registry", + "publicResource": "registry", + "operation": "deleteApiDocumentVersion", + "publicOperation": "deleteApiDocumentVersion", + "deprecated": false, + "method": "DELETE", + "path": "/v1/apis/{namespace}/{slug}/version/{semver}", + "pathParams": [ + "namespace", + "slug", + "semver" + ], + "publicPathParams": [ + "namespace", + "slug", + "semver" + ], + "queryParams": [], + "publicQueryParams": [], + "headerParams": [], + "publicHeaderParams": [], + "bodyParams": [], + "publicBodyParams": [], + "pathParamDetails": [ + { + "name": "namespace", + "required": true, + "style": "simple", + "explode": false + }, + { + "name": "slug", + "required": true, + "style": "simple", + "explode": false + }, + { + "name": "semver", + "required": true, + "style": "simple", + "explode": false + } + ], + "queryParamDetails": [], + "headerParamDetails": [], + "cookieParams": [], + "publicCookieParams": [], + "cookieParamDetails": [], + "paramsModel": { + "publicName": "RegistryDeleteApiDocumentVersionParams" + }, + "response": { + "status": "200", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ] + }, + "result": { + "successStatus": "200", + "errorStatuses": [ + "400", + "401", + "403", + "404", + "422", + "500" + ] + }, + "errorResponses": [ + { + "status": "400", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_400", + "publicAliases": [] + } + }, + { + "status": "401", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_401", + "publicAliases": [] + } + }, + { + "status": "403", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_403", + "publicAliases": [] + } + }, + { + "status": "404", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_404", + "publicAliases": [] + } + }, + { + "status": "422", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_422", + "publicAliases": [] + } + }, + { + "status": "500", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_500", + "publicAliases": [] + } + } + ], + "responseLinks": [], + "transport": "http" + }, + { + "resource": "registry", + "publicResource": "registry", + "operation": "listApiDocumentVersionMetadata", + "publicOperation": "listApiDocumentVersionMetadata", + "deprecated": false, + "method": "GET", + "path": "/v1/apis/{namespace}/{slug}/version/{semver}/metadata", + "pathParams": [ + "namespace", + "slug", + "semver" + ], + "publicPathParams": [ + "namespace", + "slug", + "semver" + ], + "queryParams": [], + "publicQueryParams": [], + "headerParams": [], + "publicHeaderParams": [], + "bodyParams": [], + "publicBodyParams": [], + "pathParamDetails": [ + { + "name": "namespace", + "required": true, + "style": "simple", + "explode": false + }, + { + "name": "slug", + "required": true, + "style": "simple", + "explode": false + }, + { + "name": "semver", + "required": true, + "style": "simple", + "explode": false + } + ], + "queryParamDetails": [], + "headerParamDetails": [], + "cookieParams": [], + "publicCookieParams": [], + "cookieParamDetails": [], + "paramsModel": { + "publicName": "RegistryListApiDocumentVersionMetadataParams" + }, + "response": { + "status": "200", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ] + }, + "responseModel": { + "name": "ManagedDocVersion", + "publicAliases": [] + }, + "result": { + "successStatus": "200", + "errorStatuses": [ + "400", + "401", + "403", + "404", + "422", + "500" + ] + }, + "errorResponses": [ + { + "status": "400", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_400", + "publicAliases": [] + } + }, + { + "status": "401", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_401", + "publicAliases": [] + } + }, + { + "status": "403", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_403", + "publicAliases": [] + } + }, + { + "status": "404", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_404", + "publicAliases": [] + } + }, + { + "status": "422", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_422", + "publicAliases": [] + } + }, + { + "status": "500", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_500", + "publicAliases": [] + } + } + ], + "responseLinks": [], + "transport": "http" + }, + { + "resource": "registry", + "publicResource": "registry", + "operation": "createApiDocumentVersion", + "publicOperation": "createApiDocumentVersion", + "deprecated": false, + "method": "POST", + "path": "/v1/apis/{namespace}/{slug}/version", + "pathParams": [ + "namespace", + "slug" + ], + "publicPathParams": [ + "namespace", + "slug" + ], + "queryParams": [], + "publicQueryParams": [], + "headerParams": [], + "publicHeaderParams": [], + "bodyParams": [ + "version", + "document", + "force", + "lastKnownVersionSha" + ], + "publicBodyParams": [ + "version", + "document", + "force", + "lastKnownVersionSha" + ], + "pathParamDetails": [ + { + "name": "namespace", + "required": true, + "style": "simple", + "explode": false + }, + { + "name": "slug", + "required": true, + "style": "simple", + "explode": false + } + ], + "queryParamDetails": [], + "headerParamDetails": [], + "cookieParams": [], + "publicCookieParams": [], + "cookieParamDetails": [], + "paramsModel": { + "publicName": "RegistryCreateApiDocumentVersionParams" + }, + "requestBody": { + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "required": true, + "publicName": "body", + "publicIdentifier": "body" + }, + "response": { + "status": "200", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ] + }, + "responseModel": { + "name": "ManagedDocVersion", + "publicAliases": [] + }, + "result": { + "successStatus": "200", + "errorStatuses": [ + "400", + "401", + "403", + "404", + "422", + "500" + ] + }, + "errorResponses": [ + { + "status": "400", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_400", + "publicAliases": [] + } + }, + { + "status": "401", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_401", + "publicAliases": [] + } + }, + { + "status": "403", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_403", + "publicAliases": [] + } + }, + { + "status": "404", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_404", + "publicAliases": [] + } + }, + { + "status": "422", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_422", + "publicAliases": [] + } + }, + { + "status": "500", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_500", + "publicAliases": [] + } + } + ], + "responseLinks": [], + "transport": "http" + }, + { + "resource": "registry", + "publicResource": "registry", + "operation": "createApiDocumentAccessGroup", + "publicOperation": "createApiDocumentAccessGroup", + "deprecated": false, + "method": "POST", + "path": "/v1/apis/{namespace}/{slug}/access-group", + "pathParams": [ + "namespace", + "slug" + ], + "publicPathParams": [ + "namespace", + "slug" + ], + "queryParams": [], + "publicQueryParams": [], + "headerParams": [], + "publicHeaderParams": [], + "bodyParams": [ + "accessGroupSlug" + ], + "publicBodyParams": [ + "accessGroupSlug" + ], + "pathParamDetails": [ + { + "name": "namespace", + "required": true, + "style": "simple", + "explode": false + }, + { + "name": "slug", + "required": true, + "style": "simple", + "explode": false + } + ], + "queryParamDetails": [], + "headerParamDetails": [], + "cookieParams": [], + "publicCookieParams": [], + "cookieParamDetails": [], + "paramsModel": { + "publicName": "RegistryCreateApiDocumentAccessGroupParams" + }, + "requestBody": { + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "required": true, + "publicName": "body", + "publicIdentifier": "body" + }, + "response": { + "status": "200", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ] + }, + "result": { + "successStatus": "200", + "errorStatuses": [ + "400", + "401", + "403", + "404", + "422", + "500" + ] + }, + "errorResponses": [ + { + "status": "400", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_400", + "publicAliases": [] + } + }, + { + "status": "401", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_401", + "publicAliases": [] + } + }, + { + "status": "403", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_403", + "publicAliases": [] + } + }, + { + "status": "404", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_404", + "publicAliases": [] + } + }, + { + "status": "422", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_422", + "publicAliases": [] + } + }, + { + "status": "500", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_500", + "publicAliases": [] + } + } + ], + "responseLinks": [], + "transport": "http" + }, + { + "resource": "registry", + "publicResource": "registry", + "operation": "deleteApiDocumentAccessGroup", + "publicOperation": "deleteApiDocumentAccessGroup", + "deprecated": false, + "method": "DELETE", + "path": "/v1/apis/{namespace}/{slug}/access-group", + "pathParams": [ + "namespace", + "slug" + ], + "publicPathParams": [ + "namespace", + "slug" + ], + "queryParams": [], + "publicQueryParams": [], + "headerParams": [], + "publicHeaderParams": [], + "bodyParams": [ + "accessGroupSlug" + ], + "publicBodyParams": [ + "accessGroupSlug" + ], + "pathParamDetails": [ + { + "name": "namespace", + "required": true, + "style": "simple", + "explode": false + }, + { + "name": "slug", + "required": true, + "style": "simple", + "explode": false + } + ], + "queryParamDetails": [], + "headerParamDetails": [], + "cookieParams": [], + "publicCookieParams": [], + "cookieParamDetails": [], + "paramsModel": { + "publicName": "RegistryDeleteApiDocumentAccessGroupParams" + }, + "requestBody": { + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "required": true, + "publicName": "body", + "publicIdentifier": "body" + }, + "response": { + "status": "200", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ] + }, + "result": { + "successStatus": "200", + "errorStatuses": [ + "400", + "401", + "403", + "404", + "422", + "500" + ] + }, + "errorResponses": [ + { + "status": "400", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_400", + "publicAliases": [] + } + }, + { + "status": "401", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_401", + "publicAliases": [] + } + }, + { + "status": "403", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_403", + "publicAliases": [] + } + }, + { + "status": "404", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_404", + "publicAliases": [] + } + }, + { + "status": "422", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_422", + "publicAliases": [] + } + }, + { + "status": "500", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_500", + "publicAliases": [] + } + } + ], + "responseLinks": [], + "transport": "http" + }, + { + "resource": "schemas", + "publicResource": "schemas", + "operation": "list", + "publicOperation": "list", + "deprecated": false, + "method": "GET", + "path": "/v1/schemas/{namespace}", + "pathParams": [ + "namespace" + ], + "publicPathParams": [ + "namespace" + ], + "queryParams": [], + "publicQueryParams": [], + "headerParams": [], + "publicHeaderParams": [], + "bodyParams": [], + "publicBodyParams": [], + "pathParamDetails": [ + { + "name": "namespace", + "required": true, + "style": "simple", + "explode": false + } + ], + "queryParamDetails": [], + "headerParamDetails": [], + "cookieParams": [], + "publicCookieParams": [], + "cookieParamDetails": [], + "paramsModel": { + "publicName": "SchemaListParams" + }, + "response": { + "status": "200", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ] + }, + "result": { + "successStatus": "200", + "errorStatuses": [ + "400", + "401", + "403", + "404", + "422", + "500" + ] + }, + "errorResponses": [ + { + "status": "400", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_400", + "publicAliases": [] + } + }, + { + "status": "401", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_401", + "publicAliases": [] + } + }, + { + "status": "403", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_403", + "publicAliases": [] + } + }, + { + "status": "404", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_404", + "publicAliases": [] + } + }, + { + "status": "422", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_422", + "publicAliases": [] + } + }, + { + "status": "500", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_500", + "publicAliases": [] + } + } + ], + "responseLinks": [], + "transport": "http" + }, + { + "resource": "schemas", + "publicResource": "schemas", + "operation": "create", + "publicOperation": "create", + "deprecated": false, + "method": "POST", + "path": "/v1/schemas/{namespace}", + "pathParams": [ + "namespace" + ], + "publicPathParams": [ + "namespace" + ], + "queryParams": [], + "publicQueryParams": [], + "headerParams": [], + "publicHeaderParams": [], + "bodyParams": [ + "title", + "description", + "version", + "slug", + "isPrivate", + "document" + ], + "publicBodyParams": [ + "title", + "description", + "version", + "slug", + "isPrivate", + "document" + ], + "pathParamDetails": [ + { + "name": "namespace", + "required": true, + "style": "simple", + "explode": false + } + ], + "queryParamDetails": [], + "headerParamDetails": [], + "cookieParams": [], + "publicCookieParams": [], + "cookieParamDetails": [], + "paramsModel": { + "publicName": "SchemaCreateParams" + }, + "requestBody": { + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "required": true, + "publicName": "body", + "publicIdentifier": "body" + }, + "response": { + "status": "200", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ] + }, + "responseModel": { + "name": "Uid", + "publicAliases": [] + }, + "result": { + "successStatus": "200", + "errorStatuses": [ + "400", + "401", + "403", + "404", + "422", + "500" + ] + }, + "errorResponses": [ + { + "status": "400", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_400", + "publicAliases": [] + } + }, + { + "status": "401", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_401", + "publicAliases": [] + } + }, + { + "status": "403", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_403", + "publicAliases": [] + } + }, + { + "status": "404", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_404", + "publicAliases": [] + } + }, + { + "status": "422", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_422", + "publicAliases": [] + } + }, + { + "status": "500", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_500", + "publicAliases": [] + } + } + ], + "responseLinks": [], + "transport": "http" + }, + { + "resource": "schemas", + "publicResource": "schemas", + "operation": "update", + "publicOperation": "update", + "deprecated": false, + "method": "PATCH", + "path": "/v1/schemas/{namespace}/{slug}", + "pathParams": [ + "namespace", + "slug" + ], + "publicPathParams": [ + "namespace", + "slug" + ], + "queryParams": [], + "publicQueryParams": [], + "headerParams": [], + "publicHeaderParams": [], + "bodyParams": [ + "title", + "description", + "isPrivate" + ], + "publicBodyParams": [ + "title", + "description", + "isPrivate" + ], + "pathParamDetails": [ + { + "name": "namespace", + "required": true, + "style": "simple", + "explode": false + }, + { + "name": "slug", + "required": true, + "style": "simple", + "explode": false + } + ], + "queryParamDetails": [], + "headerParamDetails": [], + "cookieParams": [], + "publicCookieParams": [], + "cookieParamDetails": [], + "paramsModel": { + "publicName": "SchemaUpdateParams" + }, + "requestBody": { + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "required": true, + "publicName": "body", + "publicIdentifier": "body" + }, + "response": { + "status": "200", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ] + }, + "result": { + "successStatus": "200", + "errorStatuses": [ + "400", + "401", + "403", + "404", + "422", + "500" + ] + }, + "errorResponses": [ + { + "status": "400", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_400", + "publicAliases": [] + } + }, + { + "status": "401", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_401", + "publicAliases": [] + } + }, + { + "status": "403", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_403", + "publicAliases": [] + } + }, + { + "status": "404", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_404", + "publicAliases": [] + } + }, + { + "status": "422", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_422", + "publicAliases": [] + } + }, + { + "status": "500", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_500", + "publicAliases": [] + } + } + ], + "responseLinks": [], + "transport": "http" + }, + { + "resource": "schemas", + "publicResource": "schemas", + "operation": "delete", + "publicOperation": "delete", + "deprecated": false, + "method": "DELETE", + "path": "/v1/schemas/{namespace}/{slug}", + "pathParams": [ + "namespace", + "slug" + ], + "publicPathParams": [ + "namespace", + "slug" + ], + "queryParams": [], + "publicQueryParams": [], + "headerParams": [], + "publicHeaderParams": [], + "bodyParams": [], + "publicBodyParams": [], + "pathParamDetails": [ + { + "name": "namespace", + "required": true, + "style": "simple", + "explode": false + }, + { + "name": "slug", + "required": true, + "style": "simple", + "explode": false + } + ], + "queryParamDetails": [], + "headerParamDetails": [], + "cookieParams": [], + "publicCookieParams": [], + "cookieParamDetails": [], + "paramsModel": { + "publicName": "SchemaDeleteParams" + }, + "response": { + "status": "200", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ] + }, + "result": { + "successStatus": "200", + "errorStatuses": [ + "400", + "401", + "403", + "404", + "422", + "500" + ] + }, + "errorResponses": [ + { + "status": "400", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_400", + "publicAliases": [] + } + }, + { + "status": "401", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_401", + "publicAliases": [] + } + }, + { + "status": "403", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_403", + "publicAliases": [] + } + }, + { + "status": "404", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_404", + "publicAliases": [] + } + }, + { + "status": "422", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_422", + "publicAliases": [] + } + }, + { + "status": "500", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_500", + "publicAliases": [] + } + } + ], + "responseLinks": [], + "transport": "http" + }, + { + "resource": "schemas.version", + "publicResource": "schemas.version", + "operation": "retrieveSchema", + "publicOperation": "retrieveSchema", + "deprecated": false, + "method": "GET", + "path": "/v1/schemas/{namespace}/{slug}/version/{semver}", + "pathParams": [ + "namespace", + "slug", + "semver" + ], + "publicPathParams": [ + "namespace", + "slug", + "semver" + ], + "queryParams": [], + "publicQueryParams": [], + "headerParams": [], + "publicHeaderParams": [], + "bodyParams": [], + "publicBodyParams": [], + "pathParamDetails": [ + { + "name": "namespace", + "required": true, + "style": "simple", + "explode": false + }, + { + "name": "slug", + "required": true, + "style": "simple", + "explode": false + }, + { + "name": "semver", + "required": true, + "style": "simple", + "explode": false + } + ], + "queryParamDetails": [], + "headerParamDetails": [], + "cookieParams": [], + "publicCookieParams": [], + "cookieParamDetails": [], + "paramsModel": { + "publicName": "VersionRetrieveSchemaParams" + }, + "response": { + "status": "200", + "contentType": "text/plain", + "encoding": "text", + "contents": [ + { + "contentType": "text/plain", + "encoding": "text" + } + ] + }, + "result": { + "successStatus": "200", + "errorStatuses": [ + "400", + "401", + "403", + "404", + "422", + "500" + ] + }, + "errorResponses": [ + { + "status": "400", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_400", + "publicAliases": [] + } + }, + { + "status": "401", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_401", + "publicAliases": [] + } + }, + { + "status": "403", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_403", + "publicAliases": [] + } + }, + { + "status": "404", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_404", + "publicAliases": [] + } + }, + { + "status": "422", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_422", + "publicAliases": [] + } + }, + { + "status": "500", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_500", + "publicAliases": [] + } + } + ], + "responseLinks": [], + "transport": "http" + }, + { + "resource": "schemas.version", + "publicResource": "schemas.version", + "operation": "deleteSchema", + "publicOperation": "deleteSchema", + "deprecated": false, + "method": "DELETE", + "path": "/v1/schemas/{namespace}/{slug}/version/{semver}", + "pathParams": [ + "namespace", + "slug", + "semver" + ], + "publicPathParams": [ + "namespace", + "slug", + "semver" + ], + "queryParams": [], + "publicQueryParams": [], + "headerParams": [], + "publicHeaderParams": [], + "bodyParams": [], + "publicBodyParams": [], + "pathParamDetails": [ + { + "name": "namespace", + "required": true, + "style": "simple", + "explode": false + }, + { + "name": "slug", + "required": true, + "style": "simple", + "explode": false + }, + { + "name": "semver", + "required": true, + "style": "simple", + "explode": false + } + ], + "queryParamDetails": [], + "headerParamDetails": [], + "cookieParams": [], + "publicCookieParams": [], + "cookieParamDetails": [], + "paramsModel": { + "publicName": "VersionDeleteSchemaParams" + }, + "response": { + "status": "200", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ] + }, + "result": { + "successStatus": "200", + "errorStatuses": [ + "400", + "401", + "403", + "404", + "422", + "500" + ] + }, + "errorResponses": [ + { + "status": "400", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_400", + "publicAliases": [] + } + }, + { + "status": "401", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_401", + "publicAliases": [] + } + }, + { + "status": "403", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_403", + "publicAliases": [] + } + }, + { + "status": "404", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_404", + "publicAliases": [] + } + }, + { + "status": "422", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_422", + "publicAliases": [] + } + }, + { + "status": "500", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_500", + "publicAliases": [] + } + } + ], + "responseLinks": [], + "transport": "http" + }, + { + "resource": "schemas.version", + "publicResource": "schemas.version", + "operation": "createSchema", + "publicOperation": "createSchema", + "deprecated": false, + "method": "POST", + "path": "/v1/schemas/{namespace}/{slug}/version", + "pathParams": [ + "namespace", + "slug" + ], + "publicPathParams": [ + "namespace", + "slug" + ], + "queryParams": [], + "publicQueryParams": [], + "headerParams": [], + "publicHeaderParams": [], + "bodyParams": [ + "version", + "document" + ], + "publicBodyParams": [ + "version", + "document" + ], + "pathParamDetails": [ + { + "name": "namespace", + "required": true, + "style": "simple", + "explode": false + }, + { + "name": "slug", + "required": true, + "style": "simple", + "explode": false + } + ], + "queryParamDetails": [], + "headerParamDetails": [], + "cookieParams": [], + "publicCookieParams": [], + "cookieParamDetails": [], + "paramsModel": { + "publicName": "VersionCreateSchemaParams" + }, + "requestBody": { + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "required": true, + "publicName": "body", + "publicIdentifier": "body" + }, + "response": { + "status": "200", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ] + }, + "responseModel": { + "name": "Uid", + "publicAliases": [] + }, + "result": { + "successStatus": "200", + "errorStatuses": [ + "400", + "401", + "403", + "404", + "422", + "500" + ] + }, + "errorResponses": [ + { + "status": "400", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_400", + "publicAliases": [] + } + }, + { + "status": "401", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_401", + "publicAliases": [] + } + }, + { + "status": "403", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_403", + "publicAliases": [] + } + }, + { + "status": "404", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_404", + "publicAliases": [] + } + }, + { + "status": "422", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_422", + "publicAliases": [] + } + }, + { + "status": "500", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_500", + "publicAliases": [] + } + } + ], + "responseLinks": [], + "transport": "http" + }, + { + "resource": "schemas.accessGroup", + "publicResource": "schemas.accessGroup", + "operation": "createSchema", + "publicOperation": "createSchema", + "deprecated": false, + "method": "POST", + "path": "/v1/schemas/{namespace}/{slug}/access-group", + "pathParams": [ + "namespace", + "slug" + ], + "publicPathParams": [ + "namespace", + "slug" + ], + "queryParams": [], + "publicQueryParams": [], + "headerParams": [], + "publicHeaderParams": [], + "bodyParams": [ + "accessGroupSlug" + ], + "publicBodyParams": [ + "accessGroupSlug" + ], + "pathParamDetails": [ + { + "name": "namespace", + "required": true, + "style": "simple", + "explode": false + }, + { + "name": "slug", + "required": true, + "style": "simple", + "explode": false + } + ], + "queryParamDetails": [], + "headerParamDetails": [], + "cookieParams": [], + "publicCookieParams": [], + "cookieParamDetails": [], + "paramsModel": { + "publicName": "AccessGroupCreateSchemaParams" + }, + "requestBody": { + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "required": true, + "publicName": "body", + "publicIdentifier": "body" + }, + "response": { + "status": "200", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ] + }, + "result": { + "successStatus": "200", + "errorStatuses": [ + "400", + "401", + "403", + "404", + "422", + "500" + ] + }, + "errorResponses": [ + { + "status": "400", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_400", + "publicAliases": [] + } + }, + { + "status": "401", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_401", + "publicAliases": [] + } + }, + { + "status": "403", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_403", + "publicAliases": [] + } + }, + { + "status": "404", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_404", + "publicAliases": [] + } + }, + { + "status": "422", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_422", + "publicAliases": [] + } + }, + { + "status": "500", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_500", + "publicAliases": [] + } + } + ], + "responseLinks": [], + "transport": "http" + }, + { + "resource": "schemas.accessGroup", + "publicResource": "schemas.accessGroup", + "operation": "deleteSchema", + "publicOperation": "deleteSchema", + "deprecated": false, + "method": "DELETE", + "path": "/v1/schemas/{namespace}/{slug}/access-group", + "pathParams": [ + "namespace", + "slug" + ], + "publicPathParams": [ + "namespace", + "slug" + ], + "queryParams": [], + "publicQueryParams": [], + "headerParams": [], + "publicHeaderParams": [], + "bodyParams": [ + "accessGroupSlug" + ], + "publicBodyParams": [ + "accessGroupSlug" + ], + "pathParamDetails": [ + { + "name": "namespace", + "required": true, + "style": "simple", + "explode": false + }, + { + "name": "slug", + "required": true, + "style": "simple", + "explode": false + } + ], + "queryParamDetails": [], + "headerParamDetails": [], + "cookieParams": [], + "publicCookieParams": [], + "cookieParamDetails": [], + "paramsModel": { + "publicName": "AccessGroupDeleteSchemaParams" + }, + "requestBody": { + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "required": true, + "publicName": "body", + "publicIdentifier": "body" + }, + "response": { + "status": "200", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ] + }, + "result": { + "successStatus": "200", + "errorStatuses": [ + "400", + "401", + "403", + "404", + "422", + "500" + ] + }, + "errorResponses": [ + { + "status": "400", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_400", + "publicAliases": [] + } + }, + { + "status": "401", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_401", + "publicAliases": [] + } + }, + { + "status": "403", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_403", + "publicAliases": [] + } + }, + { + "status": "404", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_404", + "publicAliases": [] + } + }, + { + "status": "422", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_422", + "publicAliases": [] + } + }, + { + "status": "500", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_500", + "publicAliases": [] + } + } + ], + "responseLinks": [], + "transport": "http" + }, + { + "resource": "loginPortals", + "publicResource": "loginPortals", + "operation": "retrieve", + "publicOperation": "retrieve", + "deprecated": false, + "method": "GET", + "path": "/v1/login-portals/{slug}", + "pathParams": [ + "slug" + ], + "publicPathParams": [ + "slug" + ], + "queryParams": [], + "publicQueryParams": [], + "headerParams": [], + "publicHeaderParams": [], + "bodyParams": [], + "publicBodyParams": [], + "pathParamDetails": [ + { + "name": "slug", + "required": true, + "style": "simple", + "explode": false + } + ], + "queryParamDetails": [], + "headerParamDetails": [], + "cookieParams": [], + "publicCookieParams": [], + "cookieParamDetails": [], + "paramsModel": { + "publicName": "LoginPortalRetrieveParams" + }, + "response": { + "status": "200", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ] + }, + "result": { + "successStatus": "200", + "errorStatuses": [ + "400", + "401", + "403", + "404", + "422", + "500" + ] + }, + "errorResponses": [ + { + "status": "400", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_400", + "publicAliases": [] + } + }, + { + "status": "401", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_401", + "publicAliases": [] + } + }, + { + "status": "403", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_403", + "publicAliases": [] + } + }, + { + "status": "404", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_404", + "publicAliases": [] + } + }, + { + "status": "422", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_422", + "publicAliases": [] + } + }, + { + "status": "500", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_500", + "publicAliases": [] + } + } + ], + "responseLinks": [], + "transport": "http" + }, + { + "resource": "loginPortals", + "publicResource": "loginPortals", + "operation": "update", + "publicOperation": "update", + "deprecated": false, + "method": "PATCH", + "path": "/v1/login-portals/{slug}", + "pathParams": [ + "slug" + ], + "publicPathParams": [ + "slug" + ], + "queryParams": [], + "publicQueryParams": [], + "headerParams": [], + "publicHeaderParams": [], + "bodyParams": [ + "title" + ], + "publicBodyParams": [ + "title" + ], + "pathParamDetails": [ + { + "name": "slug", + "required": true, + "style": "simple", + "explode": false + } + ], + "queryParamDetails": [], + "headerParamDetails": [], + "cookieParams": [], + "publicCookieParams": [], + "cookieParamDetails": [], + "paramsModel": { + "publicName": "LoginPortalUpdateParams" + }, + "requestBody": { + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "required": true, + "publicName": "body", + "publicIdentifier": "body" + }, + "response": { + "status": "200", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ] + }, + "result": { + "successStatus": "200", + "errorStatuses": [ + "400", + "401", + "403", + "404", + "422", + "500" + ] + }, + "errorResponses": [ + { + "status": "400", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_400", + "publicAliases": [] + } + }, + { + "status": "401", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_401", + "publicAliases": [] + } + }, + { + "status": "403", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_403", + "publicAliases": [] + } + }, + { + "status": "404", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_404", + "publicAliases": [] + } + }, + { + "status": "422", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_422", + "publicAliases": [] + } + }, + { + "status": "500", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_500", + "publicAliases": [] + } + } + ], + "responseLinks": [], + "transport": "http" + }, + { + "resource": "loginPortals", + "publicResource": "loginPortals", + "operation": "delete", + "publicOperation": "delete", + "deprecated": false, + "method": "DELETE", + "path": "/v1/login-portals/{slug}", + "pathParams": [ + "slug" + ], + "publicPathParams": [ + "slug" + ], + "queryParams": [], + "publicQueryParams": [], + "headerParams": [], + "publicHeaderParams": [], + "bodyParams": [], + "publicBodyParams": [], + "pathParamDetails": [ + { + "name": "slug", + "required": true, + "style": "simple", + "explode": false + } + ], + "queryParamDetails": [], + "headerParamDetails": [], + "cookieParams": [], + "publicCookieParams": [], + "cookieParamDetails": [], + "paramsModel": { + "publicName": "LoginPortalDeleteParams" + }, + "response": { + "status": "200", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ] + }, + "result": { + "successStatus": "200", + "errorStatuses": [ + "400", + "401", + "403", + "404", + "422", + "500" + ] + }, + "errorResponses": [ + { + "status": "400", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_400", + "publicAliases": [] + } + }, + { + "status": "401", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_401", + "publicAliases": [] + } + }, + { + "status": "403", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_403", + "publicAliases": [] + } + }, + { + "status": "404", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_404", + "publicAliases": [] + } + }, + { + "status": "422", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_422", + "publicAliases": [] + } + }, + { + "status": "500", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_500", + "publicAliases": [] + } + } + ], + "responseLinks": [], + "transport": "http" + }, + { + "resource": "loginPortals", + "publicResource": "loginPortals", + "operation": "create", + "publicOperation": "create", + "deprecated": false, + "method": "POST", + "path": "/v1/login-portals", + "pathParams": [], + "publicPathParams": [], + "queryParams": [], + "publicQueryParams": [], + "headerParams": [], + "publicHeaderParams": [], + "bodyParams": [ + "title", + "slug", + "email", + "page" + ], + "publicBodyParams": [ + "title", + "slug", + "email", + "page" + ], + "pathParamDetails": [], + "queryParamDetails": [], + "headerParamDetails": [], + "cookieParams": [], + "publicCookieParams": [], + "cookieParamDetails": [], + "paramsModel": { + "publicName": "LoginPortalCreateParams" + }, + "requestBody": { + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "required": true, + "publicName": "body", + "publicIdentifier": "body" + }, + "response": { + "status": "200", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ] + }, + "responseModel": { + "name": "Uid", + "publicAliases": [] + }, + "result": { + "successStatus": "200", + "errorStatuses": [ + "400", + "401", + "403", + "404", + "422", + "500" + ] + }, + "errorResponses": [ + { + "status": "400", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_400", + "publicAliases": [] + } + }, + { + "status": "401", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_401", + "publicAliases": [] + } + }, + { + "status": "403", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_403", + "publicAliases": [] + } + }, + { + "status": "404", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_404", + "publicAliases": [] + } + }, + { + "status": "422", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_422", + "publicAliases": [] + } + }, + { + "status": "500", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_500", + "publicAliases": [] + } + } + ], + "responseLinks": [], + "transport": "http" + }, + { + "resource": "loginPortals", + "publicResource": "loginPortals", + "operation": "list", + "publicOperation": "list", + "deprecated": false, + "method": "GET", + "path": "/v1/login-portals", + "pathParams": [], + "publicPathParams": [], + "queryParams": [], + "publicQueryParams": [], + "headerParams": [], + "publicHeaderParams": [], + "bodyParams": [], + "publicBodyParams": [], + "pathParamDetails": [], + "queryParamDetails": [], + "headerParamDetails": [], + "cookieParams": [], + "publicCookieParams": [], + "cookieParamDetails": [], + "response": { + "status": "200", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ] + }, + "result": { + "successStatus": "200", + "errorStatuses": [ + "400", + "401", + "403", + "404", + "422", + "500" + ] + }, + "errorResponses": [ + { + "status": "400", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_400", + "publicAliases": [] + } + }, + { + "status": "401", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_401", + "publicAliases": [] + } + }, + { + "status": "403", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_403", + "publicAliases": [] + } + }, + { + "status": "404", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_404", + "publicAliases": [] + } + }, + { + "status": "422", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_422", + "publicAliases": [] + } + }, + { + "status": "500", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_500", + "publicAliases": [] + } + } + ], + "responseLinks": [], + "transport": "http" + }, + { + "resource": "rules", + "publicResource": "rules", + "operation": "listRulesets", + "publicOperation": "listRulesets", + "deprecated": false, + "method": "GET", + "path": "/v1/rulesets/{namespace}", + "pathParams": [ + "namespace" + ], + "publicPathParams": [ + "namespace" + ], + "queryParams": [], + "publicQueryParams": [], + "headerParams": [], + "publicHeaderParams": [], + "bodyParams": [], + "publicBodyParams": [], + "pathParamDetails": [ + { + "name": "namespace", + "required": true, + "style": "simple", + "explode": false + } + ], + "queryParamDetails": [], + "headerParamDetails": [], + "cookieParams": [], + "publicCookieParams": [], + "cookieParamDetails": [], + "paramsModel": { + "publicName": "RuleListRulesetsParams" + }, + "response": { + "status": "200", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ] + }, + "result": { + "successStatus": "200", + "errorStatuses": [ + "400", + "401", + "403", + "404", + "422", + "500" + ] + }, + "errorResponses": [ + { + "status": "400", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_400", + "publicAliases": [] + } + }, + { + "status": "401", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_401", + "publicAliases": [] + } + }, + { + "status": "403", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_403", + "publicAliases": [] + } + }, + { + "status": "404", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_404", + "publicAliases": [] + } + }, + { + "status": "422", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_422", + "publicAliases": [] + } + }, + { + "status": "500", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_500", + "publicAliases": [] + } + } + ], + "responseLinks": [], + "transport": "http" + }, + { + "resource": "rules", + "publicResource": "rules", + "operation": "createRuleset", + "publicOperation": "createRuleset", + "deprecated": false, + "method": "POST", + "path": "/v1/rulesets/{namespace}", + "pathParams": [ + "namespace" + ], + "publicPathParams": [ + "namespace" + ], + "queryParams": [], + "publicQueryParams": [], + "headerParams": [], + "publicHeaderParams": [], + "bodyParams": [ + "title", + "description", + "slug", + "isPrivate", + "document" + ], + "publicBodyParams": [ + "title", + "description", + "slug", + "isPrivate", + "document" + ], + "pathParamDetails": [ + { + "name": "namespace", + "required": true, + "style": "simple", + "explode": false + } + ], + "queryParamDetails": [], + "headerParamDetails": [], + "cookieParams": [], + "publicCookieParams": [], + "cookieParamDetails": [], + "paramsModel": { + "publicName": "RuleCreateRulesetParams" + }, + "requestBody": { + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "required": true, + "publicName": "body", + "publicIdentifier": "body" + }, + "response": { + "status": "200", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ] + }, + "responseModel": { + "name": "Uid", + "publicAliases": [] + }, + "result": { + "successStatus": "200", + "errorStatuses": [ + "400", + "401", + "403", + "404", + "422", + "500" + ] + }, + "errorResponses": [ + { + "status": "400", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_400", + "publicAliases": [] + } + }, + { + "status": "401", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_401", + "publicAliases": [] + } + }, + { + "status": "403", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_403", + "publicAliases": [] + } + }, + { + "status": "404", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_404", + "publicAliases": [] + } + }, + { + "status": "422", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_422", + "publicAliases": [] + } + }, + { + "status": "500", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_500", + "publicAliases": [] + } + } + ], + "responseLinks": [], + "transport": "http" + }, + { + "resource": "rules", + "publicResource": "rules", + "operation": "updateRuleset", + "publicOperation": "updateRuleset", + "deprecated": false, + "method": "PATCH", + "path": "/v1/rulesets/{namespace}/{slug}", + "pathParams": [ + "namespace", + "slug" + ], + "publicPathParams": [ + "namespace", + "slug" + ], + "queryParams": [], + "publicQueryParams": [], + "headerParams": [], + "publicHeaderParams": [], + "bodyParams": [ + "namespace", + "slug", + "title", + "description", + "isPrivate" + ], + "publicBodyParams": [ + "namespace", + "slug", + "title", + "description", + "isPrivate" + ], + "pathParamDetails": [ + { + "name": "namespace", + "required": true, + "style": "simple", + "explode": false + }, + { + "name": "slug", + "required": true, + "style": "simple", + "explode": false + } + ], + "queryParamDetails": [], + "headerParamDetails": [], + "cookieParams": [], + "publicCookieParams": [], + "cookieParamDetails": [], + "paramsModel": { + "publicName": "RuleUpdateRulesetParams" + }, + "requestBody": { + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "required": true, + "publicName": "body", + "publicIdentifier": "body" + }, + "response": { + "status": "200", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ] + }, + "result": { + "successStatus": "200", + "errorStatuses": [ + "400", + "401", + "403", + "404", + "422", + "500" + ] + }, + "errorResponses": [ + { + "status": "400", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_400", + "publicAliases": [] + } + }, + { + "status": "401", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_401", + "publicAliases": [] + } + }, + { + "status": "403", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_403", + "publicAliases": [] + } + }, + { + "status": "404", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_404", + "publicAliases": [] + } + }, + { + "status": "422", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_422", + "publicAliases": [] + } + }, + { + "status": "500", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_500", + "publicAliases": [] + } + } + ], + "responseLinks": [], + "transport": "http" + }, + { + "resource": "rules", + "publicResource": "rules", + "operation": "deleteRuleset", + "publicOperation": "deleteRuleset", + "deprecated": false, + "method": "DELETE", + "path": "/v1/rulesets/{namespace}/{slug}", + "pathParams": [ + "namespace", + "slug" + ], + "publicPathParams": [ + "namespace", + "slug" + ], + "queryParams": [], + "publicQueryParams": [], + "headerParams": [], + "publicHeaderParams": [], + "bodyParams": [], + "publicBodyParams": [], + "pathParamDetails": [ + { + "name": "namespace", + "required": true, + "style": "simple", + "explode": false + }, + { + "name": "slug", + "required": true, + "style": "simple", + "explode": false + } + ], + "queryParamDetails": [], + "headerParamDetails": [], + "cookieParams": [], + "publicCookieParams": [], + "cookieParamDetails": [], + "paramsModel": { + "publicName": "RuleDeleteRulesetParams" + }, + "response": { + "status": "200", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ] + }, + "result": { + "successStatus": "200", + "errorStatuses": [ + "400", + "401", + "403", + "404", + "422", + "500" + ] + }, + "errorResponses": [ + { + "status": "400", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_400", + "publicAliases": [] + } + }, + { + "status": "401", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_401", + "publicAliases": [] + } + }, + { + "status": "403", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_403", + "publicAliases": [] + } + }, + { + "status": "404", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_404", + "publicAliases": [] + } + }, + { + "status": "422", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_422", + "publicAliases": [] + } + }, + { + "status": "500", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_500", + "publicAliases": [] + } + } + ], + "responseLinks": [], + "transport": "http" + }, + { + "resource": "rules", + "publicResource": "rules", + "operation": "retrieveRulesetDocument", + "publicOperation": "retrieveRulesetDocument", + "deprecated": false, + "method": "GET", + "path": "/v1/rulesets/{namespace}/{slug}", + "pathParams": [ + "namespace", + "slug" + ], + "publicPathParams": [ + "namespace", + "slug" + ], + "queryParams": [], + "publicQueryParams": [], + "headerParams": [], + "publicHeaderParams": [], + "bodyParams": [], + "publicBodyParams": [], + "pathParamDetails": [ + { + "name": "namespace", + "required": true, + "style": "simple", + "explode": false + }, + { + "name": "slug", + "required": true, + "style": "simple", + "explode": false + } + ], + "queryParamDetails": [], + "headerParamDetails": [], + "cookieParams": [], + "publicCookieParams": [], + "cookieParamDetails": [], + "paramsModel": { + "publicName": "RuleRetrieveRulesetDocumentParams" + }, + "response": { + "status": "200", + "contentType": "text/plain", + "encoding": "text", + "contents": [ + { + "contentType": "text/plain", + "encoding": "text" + } + ] + }, + "result": { + "successStatus": "200", + "errorStatuses": [ + "400", + "401", + "403", + "404", + "422", + "500" + ] + }, + "errorResponses": [ + { + "status": "400", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_400", + "publicAliases": [] + } + }, + { + "status": "401", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_401", + "publicAliases": [] + } + }, + { + "status": "403", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_403", + "publicAliases": [] + } + }, + { + "status": "404", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_404", + "publicAliases": [] + } + }, + { + "status": "422", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_422", + "publicAliases": [] + } + }, + { + "status": "500", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_500", + "publicAliases": [] + } + } + ], + "responseLinks": [], + "transport": "http" + }, + { + "resource": "rules", + "publicResource": "rules", + "operation": "createRulesetAccessGroup", + "publicOperation": "createRulesetAccessGroup", + "deprecated": false, + "method": "POST", + "path": "/v1/rulesets/{namespace}/{slug}/access-group", + "pathParams": [ + "namespace", + "slug" + ], + "publicPathParams": [ + "namespace", + "slug" + ], + "queryParams": [], + "publicQueryParams": [], + "headerParams": [], + "publicHeaderParams": [], + "bodyParams": [ + "accessGroupSlug" + ], + "publicBodyParams": [ + "accessGroupSlug" + ], + "pathParamDetails": [ + { + "name": "namespace", + "required": true, + "style": "simple", + "explode": false + }, + { + "name": "slug", + "required": true, + "style": "simple", + "explode": false + } + ], + "queryParamDetails": [], + "headerParamDetails": [], + "cookieParams": [], + "publicCookieParams": [], + "cookieParamDetails": [], + "paramsModel": { + "publicName": "RuleCreateRulesetAccessGroupParams" + }, + "requestBody": { + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "required": true, + "publicName": "body", + "publicIdentifier": "body" + }, + "response": { + "status": "200", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ] + }, + "result": { + "successStatus": "200", + "errorStatuses": [ + "400", + "401", + "403", + "404", + "422", + "500" + ] + }, + "errorResponses": [ + { + "status": "400", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_400", + "publicAliases": [] + } + }, + { + "status": "401", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_401", + "publicAliases": [] + } + }, + { + "status": "403", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_403", + "publicAliases": [] + } + }, + { + "status": "404", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_404", + "publicAliases": [] + } + }, + { + "status": "422", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_422", + "publicAliases": [] + } + }, + { + "status": "500", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_500", + "publicAliases": [] + } + } + ], + "responseLinks": [], + "transport": "http" + }, + { + "resource": "rules", + "publicResource": "rules", + "operation": "deleteRulesetAccessGroup", + "publicOperation": "deleteRulesetAccessGroup", + "deprecated": false, + "method": "DELETE", + "path": "/v1/rulesets/{namespace}/{slug}/access-group", + "pathParams": [ + "namespace", + "slug" + ], + "publicPathParams": [ + "namespace", + "slug" + ], + "queryParams": [], + "publicQueryParams": [], + "headerParams": [], + "publicHeaderParams": [], + "bodyParams": [ + "accessGroupSlug" + ], + "publicBodyParams": [ + "accessGroupSlug" + ], + "pathParamDetails": [ + { + "name": "namespace", + "required": true, + "style": "simple", + "explode": false + }, + { + "name": "slug", + "required": true, + "style": "simple", + "explode": false + } + ], + "queryParamDetails": [], + "headerParamDetails": [], + "cookieParams": [], + "publicCookieParams": [], + "cookieParamDetails": [], + "paramsModel": { + "publicName": "RuleDeleteRulesetAccessGroupParams" + }, + "requestBody": { + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "required": true, + "publicName": "body", + "publicIdentifier": "body" + }, + "response": { + "status": "200", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ] + }, + "result": { + "successStatus": "200", + "errorStatuses": [ + "400", + "401", + "403", + "404", + "422", + "500" + ] + }, + "errorResponses": [ + { + "status": "400", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_400", + "publicAliases": [] + } + }, + { + "status": "401", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_401", + "publicAliases": [] + } + }, + { + "status": "403", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_403", + "publicAliases": [] + } + }, + { + "status": "404", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_404", + "publicAliases": [] + } + }, + { + "status": "422", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_422", + "publicAliases": [] + } + }, + { + "status": "500", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_500", + "publicAliases": [] + } + } + ], + "responseLinks": [], + "transport": "http" + }, + { + "resource": "themes", + "publicResource": "themes", + "operation": "list", + "publicOperation": "list", + "deprecated": false, + "method": "GET", + "path": "/v1/themes", + "pathParams": [], + "publicPathParams": [], + "queryParams": [], + "publicQueryParams": [], + "headerParams": [], + "publicHeaderParams": [], + "bodyParams": [], + "publicBodyParams": [], + "pathParamDetails": [], + "queryParamDetails": [], + "headerParamDetails": [], + "cookieParams": [], + "publicCookieParams": [], + "cookieParamDetails": [], + "response": { + "status": "200", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ] + }, + "result": { + "successStatus": "200", + "errorStatuses": [ + "400", + "401", + "403", + "404", + "422", + "500" + ] + }, + "errorResponses": [ + { + "status": "400", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_400", + "publicAliases": [] + } + }, + { + "status": "401", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_401", + "publicAliases": [] + } + }, + { + "status": "403", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_403", + "publicAliases": [] + } + }, + { + "status": "404", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_404", + "publicAliases": [] + } + }, + { + "status": "422", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_422", + "publicAliases": [] + } + }, + { + "status": "500", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_500", + "publicAliases": [] + } + } + ], + "responseLinks": [], + "transport": "http" + }, + { + "resource": "themes", + "publicResource": "themes", + "operation": "create", + "publicOperation": "create", + "deprecated": false, + "method": "POST", + "path": "/v1/themes", + "pathParams": [], + "publicPathParams": [], + "queryParams": [], + "publicQueryParams": [], + "headerParams": [], + "publicHeaderParams": [], + "bodyParams": [ + "name", + "description", + "slug", + "document" + ], + "publicBodyParams": [ + "name", + "description", + "slug", + "document" + ], + "pathParamDetails": [], + "queryParamDetails": [], + "headerParamDetails": [], + "cookieParams": [], + "publicCookieParams": [], + "cookieParamDetails": [], + "paramsModel": { + "publicName": "ThemeCreateParams" + }, + "requestBody": { + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "required": true, + "publicName": "body", + "publicIdentifier": "body" + }, + "response": { + "status": "200", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ] + }, + "responseModel": { + "name": "Uid", + "publicAliases": [] + }, + "result": { + "successStatus": "200", + "errorStatuses": [ + "400", + "401", + "403", + "404", + "422", + "500" + ] + }, + "errorResponses": [ + { + "status": "400", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_400", + "publicAliases": [] + } + }, + { + "status": "401", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_401", + "publicAliases": [] + } + }, + { + "status": "403", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_403", + "publicAliases": [] + } + }, + { + "status": "404", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_404", + "publicAliases": [] + } + }, + { + "status": "422", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_422", + "publicAliases": [] + } + }, + { + "status": "500", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_500", + "publicAliases": [] + } + } + ], + "responseLinks": [], + "transport": "http" + }, + { + "resource": "themes", + "publicResource": "themes", + "operation": "update", + "publicOperation": "update", + "deprecated": false, + "method": "PATCH", + "path": "/v1/themes/{slug}", + "pathParams": [ + "slug" + ], + "publicPathParams": [ + "slug" + ], + "queryParams": [], + "publicQueryParams": [], + "headerParams": [], + "publicHeaderParams": [], + "bodyParams": [ + "name", + "description" + ], + "publicBodyParams": [ + "name", + "description" + ], + "pathParamDetails": [ + { + "name": "slug", + "required": true, + "style": "simple", + "explode": false + } + ], + "queryParamDetails": [], + "headerParamDetails": [], + "cookieParams": [], + "publicCookieParams": [], + "cookieParamDetails": [], + "paramsModel": { + "publicName": "ThemeUpdateParams" + }, + "requestBody": { + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "required": true, + "publicName": "body", + "publicIdentifier": "body" + }, + "response": { + "status": "200", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ] + }, + "result": { + "successStatus": "200", + "errorStatuses": [ + "400", + "401", + "403", + "404", + "422", + "500" + ] + }, + "errorResponses": [ + { + "status": "400", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_400", + "publicAliases": [] + } + }, + { + "status": "401", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_401", + "publicAliases": [] + } + }, + { + "status": "403", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_403", + "publicAliases": [] + } + }, + { + "status": "404", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_404", + "publicAliases": [] + } + }, + { + "status": "422", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_422", + "publicAliases": [] + } + }, + { + "status": "500", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_500", + "publicAliases": [] + } + } + ], + "responseLinks": [], + "transport": "http" + }, + { + "resource": "themes", + "publicResource": "themes", + "operation": "replaceDocument", + "publicOperation": "replaceDocument", + "deprecated": false, + "method": "PUT", + "path": "/v1/themes/{slug}", + "pathParams": [ + "slug" + ], + "publicPathParams": [ + "slug" + ], + "queryParams": [], + "publicQueryParams": [], + "headerParams": [], + "publicHeaderParams": [], + "bodyParams": [ + "document" + ], + "publicBodyParams": [ + "document" + ], + "pathParamDetails": [ + { + "name": "slug", + "required": true, + "style": "simple", + "explode": false + } + ], + "queryParamDetails": [], + "headerParamDetails": [], + "cookieParams": [], + "publicCookieParams": [], + "cookieParamDetails": [], + "paramsModel": { + "publicName": "ThemeReplaceDocumentParams" + }, + "requestBody": { + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "required": true, + "publicName": "body", + "publicIdentifier": "body" + }, + "response": { + "status": "200", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ] + }, + "result": { + "successStatus": "200", + "errorStatuses": [ + "400", + "401", + "403", + "404", + "422", + "500" + ] + }, + "errorResponses": [ + { + "status": "400", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_400", + "publicAliases": [] + } + }, + { + "status": "401", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_401", + "publicAliases": [] + } + }, + { + "status": "403", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_403", + "publicAliases": [] + } + }, + { + "status": "404", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_404", + "publicAliases": [] + } + }, + { + "status": "422", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_422", + "publicAliases": [] + } + }, + { + "status": "500", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_500", + "publicAliases": [] + } + } + ], + "responseLinks": [], + "transport": "http" + }, + { + "resource": "themes", + "publicResource": "themes", + "operation": "delete", + "publicOperation": "delete", + "deprecated": false, + "method": "DELETE", + "path": "/v1/themes/{slug}", + "pathParams": [ + "slug" + ], + "publicPathParams": [ + "slug" + ], + "queryParams": [], + "publicQueryParams": [], + "headerParams": [], + "publicHeaderParams": [], + "bodyParams": [], + "publicBodyParams": [], + "pathParamDetails": [ + { + "name": "slug", + "required": true, + "style": "simple", + "explode": false + } + ], + "queryParamDetails": [], + "headerParamDetails": [], + "cookieParams": [], + "publicCookieParams": [], + "cookieParamDetails": [], + "paramsModel": { + "publicName": "ThemeDeleteParams" + }, + "response": { + "status": "200", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ] + }, + "result": { + "successStatus": "200", + "errorStatuses": [ + "400", + "401", + "403", + "404", + "422", + "500" + ] + }, + "errorResponses": [ + { + "status": "400", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_400", + "publicAliases": [] + } + }, + { + "status": "401", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_401", + "publicAliases": [] + } + }, + { + "status": "403", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_403", + "publicAliases": [] + } + }, + { + "status": "404", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_404", + "publicAliases": [] + } + }, + { + "status": "422", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_422", + "publicAliases": [] + } + }, + { + "status": "500", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_500", + "publicAliases": [] + } + } + ], + "responseLinks": [], + "transport": "http" + }, + { + "resource": "themes", + "publicResource": "themes", + "operation": "retrieve", + "publicOperation": "retrieve", + "deprecated": false, + "method": "GET", + "path": "/v1/themes/{slug}", + "pathParams": [ + "slug" + ], + "publicPathParams": [ + "slug" + ], + "queryParams": [], + "publicQueryParams": [], + "headerParams": [], + "publicHeaderParams": [], + "bodyParams": [], + "publicBodyParams": [], + "pathParamDetails": [ + { + "name": "slug", + "required": true, + "style": "simple", + "explode": false + } + ], + "queryParamDetails": [], + "headerParamDetails": [], + "cookieParams": [], + "publicCookieParams": [], + "cookieParamDetails": [], + "paramsModel": { + "publicName": "ThemeRetrieveParams" + }, + "response": { + "status": "200", + "contentType": "text/plain", + "encoding": "text", + "contents": [ + { + "contentType": "text/plain", + "encoding": "text" + } + ] + }, + "result": { + "successStatus": "200", + "errorStatuses": [ + "400", + "401", + "403", + "404", + "422", + "500" + ] + }, + "errorResponses": [ + { + "status": "400", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_400", + "publicAliases": [] + } + }, + { + "status": "401", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_401", + "publicAliases": [] + } + }, + { + "status": "403", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_403", + "publicAliases": [] + } + }, + { + "status": "404", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_404", + "publicAliases": [] + } + }, + { + "status": "422", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_422", + "publicAliases": [] + } + }, + { + "status": "500", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_500", + "publicAliases": [] + } + } + ], + "responseLinks": [], + "transport": "http" + }, + { + "resource": "teams", + "publicResource": "teams", + "operation": "list", + "publicOperation": "list", + "deprecated": false, + "method": "GET", + "path": "/v1/teams", + "pathParams": [], + "publicPathParams": [], + "queryParams": [], + "publicQueryParams": [], + "headerParams": [], + "publicHeaderParams": [], + "bodyParams": [], + "publicBodyParams": [], + "pathParamDetails": [], + "queryParamDetails": [], + "headerParamDetails": [], + "cookieParams": [], + "publicCookieParams": [], + "cookieParamDetails": [], + "response": { + "status": "200", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ] + }, + "result": { + "successStatus": "200", + "errorStatuses": [ + "400", + "401", + "403", + "404", + "422", + "500" + ] + }, + "errorResponses": [ + { + "status": "400", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_400", + "publicAliases": [] + } + }, + { + "status": "401", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_401", + "publicAliases": [] + } + }, + { + "status": "403", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_403", + "publicAliases": [] + } + }, + { + "status": "404", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_404", + "publicAliases": [] + } + }, + { + "status": "422", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_422", + "publicAliases": [] + } + }, + { + "status": "500", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_500", + "publicAliases": [] + } + } + ], + "responseLinks": [], + "transport": "http" + }, + { + "resource": "scalarDocs", + "publicResource": "scalarDocs", + "operation": "listGuides", + "publicOperation": "listGuides", + "deprecated": false, + "method": "GET", + "path": "/v1/guides", + "pathParams": [], + "publicPathParams": [], + "queryParams": [], + "publicQueryParams": [], + "headerParams": [], + "publicHeaderParams": [], + "bodyParams": [], + "publicBodyParams": [], + "pathParamDetails": [], + "queryParamDetails": [], + "headerParamDetails": [], + "cookieParams": [], + "publicCookieParams": [], + "cookieParamDetails": [], + "response": { + "status": "200", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ] + }, + "result": { + "successStatus": "200", + "errorStatuses": [ + "400", + "401", + "403", + "404", + "422", + "500" + ] + }, + "errorResponses": [ + { + "status": "400", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_400", + "publicAliases": [] + } + }, + { + "status": "401", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_401", + "publicAliases": [] + } + }, + { + "status": "403", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_403", + "publicAliases": [] + } + }, + { + "status": "404", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_404", + "publicAliases": [] + } + }, + { + "status": "422", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_422", + "publicAliases": [] + } + }, + { + "status": "500", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_500", + "publicAliases": [] + } + } + ], + "responseLinks": [], + "transport": "http" + }, + { + "resource": "scalarDocs", + "publicResource": "scalarDocs", + "operation": "createGuide", + "publicOperation": "createGuide", + "deprecated": false, + "method": "POST", + "path": "/v1/guides", + "pathParams": [], + "publicPathParams": [], + "queryParams": [], + "publicQueryParams": [], + "headerParams": [], + "publicHeaderParams": [], + "bodyParams": [ + "name", + "slug", + "isPrivate", + "allowedUsers", + "allowedDomains" + ], + "publicBodyParams": [ + "name", + "slug", + "isPrivate", + "allowedUsers", + "allowedDomains" + ], + "pathParamDetails": [], + "queryParamDetails": [], + "headerParamDetails": [], + "cookieParams": [], + "publicCookieParams": [], + "cookieParamDetails": [], + "paramsModel": { + "publicName": "ScalarDocCreateGuideParams" + }, + "requestBody": { + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "required": true, + "publicName": "body", + "publicIdentifier": "body" + }, + "response": { + "status": "200", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ] + }, + "result": { + "successStatus": "200", + "errorStatuses": [ + "400", + "401", + "403", + "404", + "422", + "500" + ] + }, + "errorResponses": [ + { + "status": "400", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_400", + "publicAliases": [] + } + }, + { + "status": "401", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_401", + "publicAliases": [] + } + }, + { + "status": "403", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_403", + "publicAliases": [] + } + }, + { + "status": "404", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_404", + "publicAliases": [] + } + }, + { + "status": "422", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_422", + "publicAliases": [] + } + }, + { + "status": "500", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_500", + "publicAliases": [] + } + } + ], + "responseLinks": [], + "transport": "http" + }, + { + "resource": "scalarDocs", + "publicResource": "scalarDocs", + "operation": "publishGuide", + "publicOperation": "publishGuide", + "deprecated": false, + "method": "POST", + "path": "/v1/guides/{slug}/publish", + "pathParams": [ + "slug" + ], + "publicPathParams": [ + "slug" + ], + "queryParams": [], + "publicQueryParams": [], + "headerParams": [], + "publicHeaderParams": [], + "bodyParams": [], + "publicBodyParams": [], + "pathParamDetails": [ + { + "name": "slug", + "required": true, + "style": "simple", + "explode": false + } + ], + "queryParamDetails": [], + "headerParamDetails": [], + "cookieParams": [], + "publicCookieParams": [], + "cookieParamDetails": [], + "paramsModel": { + "publicName": "ScalarDocPublishGuideParams" + }, + "response": { + "status": "200", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ] + }, + "result": { + "successStatus": "200", + "errorStatuses": [ + "400", + "401", + "403", + "404", + "422", + "500" + ] + }, + "errorResponses": [ + { + "status": "400", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_400", + "publicAliases": [] + } + }, + { + "status": "401", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_401", + "publicAliases": [] + } + }, + { + "status": "403", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_403", + "publicAliases": [] + } + }, + { + "status": "404", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_404", + "publicAliases": [] + } + }, + { + "status": "422", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_422", + "publicAliases": [] + } + }, + { + "status": "500", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_500", + "publicAliases": [] + } + } + ], + "responseLinks": [], + "transport": "http" + }, + { + "resource": "namespaces", + "publicResource": "namespaces", + "operation": "list", + "publicOperation": "list", + "deprecated": false, + "method": "GET", + "path": "/v1/namespaces", + "pathParams": [], + "publicPathParams": [], + "queryParams": [], + "publicQueryParams": [], + "headerParams": [], + "publicHeaderParams": [], + "bodyParams": [], + "publicBodyParams": [], + "pathParamDetails": [], + "queryParamDetails": [], + "headerParamDetails": [], + "cookieParams": [], + "publicCookieParams": [], + "cookieParamDetails": [], + "response": { + "status": "200", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ] + }, + "result": { + "successStatus": "200", + "errorStatuses": [ + "400", + "401", + "403", + "404", + "422", + "500" + ] + }, + "errorResponses": [ + { + "status": "400", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_400", + "publicAliases": [] + } + }, + { + "status": "401", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_401", + "publicAliases": [] + } + }, + { + "status": "403", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_403", + "publicAliases": [] + } + }, + { + "status": "404", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_404", + "publicAliases": [] + } + }, + { + "status": "422", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_422", + "publicAliases": [] + } + }, + { + "status": "500", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_500", + "publicAliases": [] + } + } + ], + "responseLinks": [], + "transport": "http" + }, + { + "resource": "authentication", + "publicResource": "authentication", + "operation": "exchangePersonalToken", + "publicOperation": "exchangePersonalToken", + "deprecated": false, + "method": "POST", + "path": "/v1/auth/exchange", + "pathParams": [], + "publicPathParams": [], + "queryParams": [], + "publicQueryParams": [], + "headerParams": [], + "publicHeaderParams": [], + "bodyParams": [ + "personalToken" + ], + "publicBodyParams": [ + "personalToken" + ], + "pathParamDetails": [], + "queryParamDetails": [], + "headerParamDetails": [], + "cookieParams": [], + "publicCookieParams": [], + "cookieParamDetails": [], + "paramsModel": { + "publicName": "AuthenticationExchangePersonalTokenParams" + }, + "requestBody": { + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "required": true, + "publicName": "body", + "publicIdentifier": "body" + }, + "response": { + "status": "200", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ] + }, + "result": { + "successStatus": "200", + "errorStatuses": [ + "400", + "401", + "403", + "404", + "422", + "500" + ] + }, + "errorResponses": [ + { + "status": "400", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_400", + "publicAliases": [] + } + }, + { + "status": "401", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_401", + "publicAliases": [] + } + }, + { + "status": "403", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_403", + "publicAliases": [] + } + }, + { + "status": "404", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_404", + "publicAliases": [] + } + }, + { + "status": "422", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_422", + "publicAliases": [] + } + }, + { + "status": "500", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_500", + "publicAliases": [] + } + } + ], + "responseLinks": [], + "transport": "http" + }, + { + "resource": "authentication", + "publicResource": "authentication", + "operation": "listCurrentUser", + "publicOperation": "listCurrentUser", + "deprecated": false, + "method": "GET", + "path": "/v1/auth/me", + "pathParams": [], + "publicPathParams": [], + "queryParams": [], + "publicQueryParams": [], + "headerParams": [], + "publicHeaderParams": [], + "bodyParams": [], + "publicBodyParams": [], + "pathParamDetails": [], + "queryParamDetails": [], + "headerParamDetails": [], + "cookieParams": [], + "publicCookieParams": [], + "cookieParamDetails": [], + "response": { + "status": "200", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ] + }, + "responseModel": { + "name": "User", + "publicAliases": [] + }, + "result": { + "successStatus": "200", + "errorStatuses": [ + "400", + "401", + "403", + "404", + "422", + "500" + ] + }, + "errorResponses": [ + { + "status": "400", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_400", + "publicAliases": [] + } + }, + { + "status": "401", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_401", + "publicAliases": [] + } + }, + { + "status": "403", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_403", + "publicAliases": [] + } + }, + { + "status": "404", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_404", + "publicAliases": [] + } + }, + { + "status": "422", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_422", + "publicAliases": [] + } + }, + { + "status": "500", + "contentType": "application/json", + "encoding": "json", + "contents": [ + { + "contentType": "application/json", + "encoding": "json" + } + ], + "model": { + "name": "_500", + "publicAliases": [] + } + } + ], + "responseLinks": [], + "transport": "http" + } + ], + "webhooks": [] +} diff --git a/src/__init__.py b/src/__init__.py new file mode 100644 index 0000000..42c7450 --- /dev/null +++ b/src/__init__.py @@ -0,0 +1,86 @@ +# File generated from our OpenAPI spec by Scalar. See README.md for details. + +import typing as _t + +from . import types +from ._types import NOT_GIVEN, Omit, NoneType, NotGiven, Transport, ProxiesTypes, omit, not_given +from ._utils import file_from_path +from ._client import Client, Stream, ScalarApi, Timeout, AsyncClient, AsyncStream, AsyncScalarApi, RequestOptions, ENVIRONMENTS +from ._models import BaseModel +from ._version import __title__, __version__ +from ._response import APIResponse as APIResponse, AsyncAPIResponse as AsyncAPIResponse +from ._constants import DEFAULT_TIMEOUT, DEFAULT_MAX_RETRIES, DEFAULT_CONNECTION_LIMITS +from ._exceptions import ( + APIError, + ScalarApiError, + ConflictError, + NotFoundError, + APIStatusError, + RateLimitError, + APITimeoutError, + BadRequestError, + APIConnectionError, + AuthenticationError, + InternalServerError, + PermissionDeniedError, + UnprocessableEntityError, + APIResponseValidationError, +) +from ._base_client import DefaultHttpxClient, DefaultAioHttpClient, DefaultAsyncHttpxClient +from ._utils._logs import setup_logging as _setup_logging + +__all__ = [ + "ENVIRONMENTS", + "types", + "__version__", + "__title__", + "NoneType", + "Transport", + "ProxiesTypes", + "NotGiven", + "NOT_GIVEN", + "not_given", + "Omit", + "omit", + "ScalarApiError", + "APIError", + "APIStatusError", + "APITimeoutError", + "APIConnectionError", + "APIResponseValidationError", + "BadRequestError", + "AuthenticationError", + "PermissionDeniedError", + "NotFoundError", + "ConflictError", + "UnprocessableEntityError", + "RateLimitError", + "InternalServerError", + "Timeout", + "RequestOptions", + "Client", + "AsyncClient", + "Stream", + "AsyncStream", + "ScalarApi", + "AsyncScalarApi", + "file_from_path", + "BaseModel", + "DEFAULT_TIMEOUT", + "DEFAULT_MAX_RETRIES", + "DEFAULT_CONNECTION_LIMITS", + "DefaultHttpxClient", + "DefaultAsyncHttpxClient", + "DefaultAioHttpClient", +] + +_setup_logging() + +__locals = locals() +__module_name = __name__ +for __export_name in __all__: + if not __export_name.startswith("__"): + try: + __locals[__export_name].__module__ = __module_name + except (TypeError, AttributeError): + pass diff --git a/src/_base_client.py b/src/_base_client.py new file mode 100644 index 0000000..f99d69d --- /dev/null +++ b/src/_base_client.py @@ -0,0 +1,2229 @@ +from __future__ import annotations + +import sys +import json +import time +import uuid +import email +import asyncio +import inspect +import logging +import platform +import warnings +import email.utils +from types import TracebackType +from random import random +from dataclasses import field, dataclass +from typing import ( + TYPE_CHECKING, + Any, + Dict, + Type, + Union, + Generic, + Mapping, + TypeVar, + Iterable, + Iterator, + Optional, + Generator, + AsyncIterator, + cast, + overload, +) +from typing_extensions import Literal, override, get_origin + +import anyio +import httpx +import distro +import pydantic +from httpx import URL +from pydantic import PrivateAttr + +from . import _exceptions +from ._qs import Querystring +from ._files import to_httpx_files, async_to_httpx_files +from ._types import ( + Body, + Omit, + Query, + Headers, + Timeout, + NotGiven, + ResponseT, + AnyMapping, + PostParser, + BinaryTypes, + RequestFiles, + HttpxSendArgs, + RequestOptions, + AsyncBinaryTypes, + HttpxRequestFiles, + ModelBuilderProtocol, + not_given, +) +from ._utils import is_dict, is_list, asyncify, is_given, lru_cache, is_mapping +from ._compat import PYDANTIC_V1, model_copy, model_dump +from ._models import GenericModel, SecurityOptions, FinalRequestOptions, validate_type, construct_type +from ._response import ( + APIResponse, + BaseAPIResponse, + AsyncAPIResponse, + extract_response_type, +) +from ._constants import ( + DEFAULT_TIMEOUT, + MAX_RETRY_DELAY, + DEFAULT_MAX_RETRIES, + INITIAL_RETRY_DELAY, + RAW_RESPONSE_HEADER, + OVERRIDE_CAST_TO_HEADER, + DEFAULT_CONNECTION_LIMITS, +) +from ._streaming import Stream, SSEDecoder, AsyncStream, SSEBytesDecoder +from ._exceptions import ( + APIStatusError, + APITimeoutError, + APIConnectionError, + APIResponseValidationError, +) +from ._utils._json import openapi_dumps + +log: logging.Logger = logging.getLogger(__name__) + +# TODO: make base page type vars covariant +SyncPageT = TypeVar("SyncPageT", bound="BaseSyncPage[Any]") +AsyncPageT = TypeVar("AsyncPageT", bound="BaseAsyncPage[Any]") + + +_T = TypeVar("_T") +_T_co = TypeVar("_T_co", covariant=True) + +_StreamT = TypeVar("_StreamT", bound=Stream[Any]) +_AsyncStreamT = TypeVar("_AsyncStreamT", bound=AsyncStream[Any]) + +if TYPE_CHECKING: + from httpx._config import ( + DEFAULT_TIMEOUT_CONFIG, # pyright: ignore[reportPrivateImportUsage] + ) + + HTTPX_DEFAULT_TIMEOUT = DEFAULT_TIMEOUT_CONFIG +else: + try: + from httpx._config import DEFAULT_TIMEOUT_CONFIG as HTTPX_DEFAULT_TIMEOUT + except ImportError: + # taken from https://github.com/encode/httpx/blob/3ba5fe0d7ac70222590e759c31442b1cab263791/httpx/_config.py#L366 + HTTPX_DEFAULT_TIMEOUT = Timeout(5.0) + + +@dataclass +class CursorPageConfig: + """Per-operation cursor pagination descriptor baked into a page by the generated list method. + + The Python view of the shared, language-neutral descriptor: where the items array lives, how to + read the next cursor, which request param carries it, and on which carrier (query vs body). + Driving extraction from this config — rather than typed `items`/`next_cursor` model fields — lets + one page class serve every cursor scheme, including `cursor_id` (cursor read from the last item) + and body-carried cursors. + """ + + # Body path to the items array (e.g. ["items"], ["data"]). + items_path: List[str] = field(default_factory=list) + # "field" (a top-level response field) or "item" (a field on the last item — `cursor_id`). + cursor_kind: str = "field" + # Path to the cursor value: from the body root when cursor_kind is "field", or from the last item. + cursor_path: List[str] = field(default_factory=list) + # Request param wire name that carries the cursor. + cursor_param: str = "cursor" + # "query" or "body": the carrier the cursor param rides on the next request. + cursor_location: str = "query" + # Keep paginating across an empty page when set. + continue_on_empty_items: bool = False + # Body path to the scheme's `has_more` boolean. Only an explicit False stops pagination; + # a missing or non-boolean value falls back to cursor-presence semantics. + has_more_path: List[str] = field(default_factory=list) + + +class PageInfo: + """Stores the necessary information to build the request to retrieve the next page. + + Exactly one of `url`, `params` (query carrier), or `json` (body carrier) must be set. + """ + + url: URL | NotGiven + params: Query | NotGiven + json: Body | NotGiven + + @overload + def __init__( + self, + *, + url: URL, + ) -> None: ... + + @overload + def __init__( + self, + *, + params: Query, + ) -> None: ... + + @overload + def __init__( + self, + *, + json: Body, + ) -> None: ... + + def __init__( + self, + *, + url: URL | NotGiven = not_given, + json: Body | NotGiven = not_given, + params: Query | NotGiven = not_given, + ) -> None: + self.url = url + self.json = json + self.params = params + + @override + def __repr__(self) -> str: + if self.url: + return f"{self.__class__.__name__}(url={self.url})" + if self.json: + return f"{self.__class__.__name__}(json={self.json})" + return f"{self.__class__.__name__}(params={self.params})" + + +class BasePage(GenericModel, Generic[_T]): + """ + Defines the core interface for pagination. + + Type Args: + ModelT: The pydantic model that represents an item in the response. + + Methods: + has_next_page(): Check if there is another page available + next_page_info(): Get the necessary information to make a request for the next page + """ + + _options: FinalRequestOptions = PrivateAttr() + _model: Type[_T] = PrivateAttr() + # Per-operation cursor descriptor; set by the paginated method via _set_private_attributes and + # carried forward across pages so every page extracts items/cursor identically. None for pages + # that predate metadata-driven pagination. + _cursor_config: Optional[CursorPageConfig] = PrivateAttr(None) + + def has_next_page(self) -> bool: + items = self._get_page_items() + if not items: + return False + return self.next_page_info() is not None + + def next_page_info(self) -> Optional[PageInfo]: ... + + def _get_page_items(self) -> Iterable[_T]: # type: ignore[empty-body] + ... + + def _params_from_url(self, url: URL) -> httpx.QueryParams: + # TODO: do we have to preprocess params here? + return httpx.QueryParams(cast(Any, self._options.params)).merge(url.params) + + def _info_to_options(self, info: PageInfo) -> FinalRequestOptions: + options = model_copy(self._options) + options._strip_raw_response_header() + + if not isinstance(info.params, NotGiven): + options.params = {**options.params, **info.params} + return options + + if not isinstance(info.url, NotGiven): + params = self._params_from_url(info.url) + url = info.url.copy_with(params=params) + options.params = dict(url.params) + options.url = str(url) + return options + + if not isinstance(info.json, NotGiven): + if not is_mapping(info.json): + raise TypeError("Pagination is only supported with mappings") + + if not options.json_data: + options.json_data = {**info.json} + else: + if not is_mapping(options.json_data): + raise TypeError("Pagination is only supported with mappings") + + options.json_data = {**options.json_data, **info.json} + return options + + raise ValueError("Unexpected PageInfo state") + + +class BaseSyncPage(BasePage[_T], Generic[_T]): + _client: SyncAPIClient = pydantic.PrivateAttr() + + def _set_private_attributes( + self, + client: SyncAPIClient, + model: Type[_T], + options: FinalRequestOptions, + cursor_config: Optional[CursorPageConfig] = None, + ) -> None: + if (not PYDANTIC_V1) and getattr(self, "__pydantic_private__", None) is None: + self.__pydantic_private__ = {} + + self._model = model + self._client = client + self._options = options + self._cursor_config = cursor_config + + # Pydantic uses a custom `__iter__` method to support casting BaseModels + # to dictionaries. e.g. dict(model). + # As we want to support `for item in page`, this is inherently incompatible + # with the default pydantic behaviour. It is not possible to support both + # use cases at once. Fortunately, this is not a big deal as all other pydantic + # methods should continue to work as expected as there is an alternative method + # to cast a model to a dictionary, model.dict(), which is used internally + # by pydantic. + def __iter__(self) -> Iterator[_T]: # type: ignore + for page in self.iter_pages(): + for item in page._get_page_items(): + yield item + + def iter_pages(self: SyncPageT) -> Iterator[SyncPageT]: + page = self + while True: + yield page + if page.has_next_page(): + page = page.get_next_page() + else: + return + + def get_next_page(self: SyncPageT) -> SyncPageT: + info = self.next_page_info() + if not info: + raise RuntimeError( + "No next page expected; please check `.has_next_page()` before calling `.get_next_page()`." + ) + + options = self._info_to_options(info) + # Carry the cursor descriptor forward so the next page extracts items/cursor identically. + return self._client._request_api_list( + self._model, page=self.__class__, options=options, cursor_config=self._cursor_config + ) + + +class AsyncPaginator(Generic[_T, AsyncPageT]): + def __init__( + self, + client: AsyncAPIClient, + options: FinalRequestOptions, + page_cls: Type[AsyncPageT], + model: Type[_T], + cursor_config: Optional[CursorPageConfig] = None, + ) -> None: + self._model = model + self._client = client + self._options = options + self._page_cls = page_cls + self._cursor_config = cursor_config + + def __await__(self) -> Generator[Any, None, AsyncPageT]: + return self._get_page().__await__() + + async def _get_page(self) -> AsyncPageT: + def _parser(resp: AsyncPageT) -> AsyncPageT: + resp._set_private_attributes( + model=self._model, + options=self._options, + client=self._client, + cursor_config=self._cursor_config, + ) + return resp + + self._options.post_parser = _parser + + return await self._client.request(self._page_cls, self._options) + + async def __aiter__(self) -> AsyncIterator[_T]: + # https://github.com/microsoft/pyright/issues/3464 + page = cast( + AsyncPageT, + await self, # type: ignore + ) + async for item in page: + yield item + + +class BaseAsyncPage(BasePage[_T], Generic[_T]): + _client: AsyncAPIClient = pydantic.PrivateAttr() + + def _set_private_attributes( + self, + model: Type[_T], + client: AsyncAPIClient, + options: FinalRequestOptions, + cursor_config: Optional[CursorPageConfig] = None, + ) -> None: + if (not PYDANTIC_V1) and getattr(self, "__pydantic_private__", None) is None: + self.__pydantic_private__ = {} + + self._model = model + self._client = client + self._options = options + self._cursor_config = cursor_config + + async def __aiter__(self) -> AsyncIterator[_T]: + async for page in self.iter_pages(): + for item in page._get_page_items(): + yield item + + async def iter_pages(self: AsyncPageT) -> AsyncIterator[AsyncPageT]: + page = self + while True: + yield page + if page.has_next_page(): + page = await page.get_next_page() + else: + return + + async def get_next_page(self: AsyncPageT) -> AsyncPageT: + info = self.next_page_info() + if not info: + raise RuntimeError( + "No next page expected; please check `.has_next_page()` before calling `.get_next_page()`." + ) + + options = self._info_to_options(info) + # Carry the cursor descriptor forward so the next page extracts items/cursor identically. + return await self._client._request_api_list( + self._model, page=self.__class__, options=options, cursor_config=self._cursor_config + ) + + +_HttpxClientT = TypeVar("_HttpxClientT", bound=Union[httpx.Client, httpx.AsyncClient]) +_DefaultStreamT = TypeVar("_DefaultStreamT", bound=Union[Stream[Any], AsyncStream[Any]]) + + +class BaseClient(Generic[_HttpxClientT, _DefaultStreamT]): + _client: _HttpxClientT + _version: str + _base_url: URL + max_retries: int + timeout: Union[float, Timeout, None] + _strict_response_validation: bool + _idempotency_header: str | None + _default_stream_cls: type[_DefaultStreamT] | None = None + + def __init__( + self, + *, + version: str, + base_url: str | URL, + _strict_response_validation: bool, + max_retries: int = DEFAULT_MAX_RETRIES, + timeout: float | Timeout | None = DEFAULT_TIMEOUT, + custom_headers: Mapping[str, str] | None = None, + custom_query: Mapping[str, object] | None = None, + ) -> None: + self._version = version + self._base_url = self._enforce_trailing_slash(URL(base_url)) + self.max_retries = max_retries + self.timeout = timeout + self._custom_headers = custom_headers or {} + self._custom_query = custom_query or {} + self._strict_response_validation = _strict_response_validation + self._idempotency_header = None + self._platform: Platform | None = None + + if max_retries is None: # pyright: ignore[reportUnnecessaryComparison] + raise TypeError( + "max_retries cannot be None. If you want to disable retries, pass `0`; if you want unlimited retries, pass `math.inf` or a very high number; if you want the default behavior, pass `scalar_api.DEFAULT_MAX_RETRIES`" + ) + + def _enforce_trailing_slash(self, url: URL) -> URL: + if url.raw_path.endswith(b"/"): + return url + return url.copy_with(raw_path=url.raw_path + b"/") + + def _make_status_error_from_response( + self, + response: httpx.Response, + ) -> APIStatusError: + if response.is_closed and not response.is_stream_consumed: + # We can't read the response body as it has been closed + # before it was read. This can happen if an event hook + # raises a status error. + body = None + err_msg = f"Error code: {response.status_code}" + else: + err_text = response.text.strip() + body = err_text + + try: + body = json.loads(err_text) + err_msg = f"Error code: {response.status_code} - {body}" + except Exception: + err_msg = err_text or f"Error code: {response.status_code}" + + return self._make_status_error(err_msg, body=body, response=response) + + def _make_status_error( + self, + err_msg: str, + *, + body: object, + response: httpx.Response, + ) -> _exceptions.APIStatusError: + raise NotImplementedError() + + def _auth_headers( + self, + security: SecurityOptions, # noqa: ARG002 + ) -> dict[str, str]: + return {} + + def _auth_query( + self, + security: SecurityOptions, # noqa: ARG002 + ) -> dict[str, str]: + return {} + + def _auth_cookies( + self, + security: SecurityOptions, # noqa: ARG002 + ) -> dict[str, str]: + return {} + + def _custom_auth( + self, + security: SecurityOptions, # noqa: ARG002 + ) -> httpx.Auth | None: + return None + + def _build_headers( + self, + options: FinalRequestOptions, + *, + params: Query, + cookies: Mapping[str, str], + retries_taken: int = 0, + ) -> httpx.Headers: + custom_headers = options.headers or {} + headers_dict = _merge_mappings({**self._auth_headers(options.security), **self.default_headers}, custom_headers) + self._validate_headers(headers_dict, custom_headers, params, cookies) + + # headers are case-insensitive while dictionaries are not. + headers = httpx.Headers(headers_dict) + + idempotency_header = self._idempotency_header + if idempotency_header and options.idempotency_key and idempotency_header not in headers: + headers[idempotency_header] = options.idempotency_key + + # Don't set these headers if they were already set or removed by the caller. We check + # `custom_headers`, which can contain `Omit()`, instead of `headers` to account for the removal case. + lower_custom_headers = [header.lower() for header in custom_headers] + if "x-scalar-retry-count" not in lower_custom_headers: + headers["x-scalar-retry-count"] = str(retries_taken) + if "x-scalar-read-timeout" not in lower_custom_headers: + timeout = self.timeout if isinstance(options.timeout, NotGiven) else options.timeout + if isinstance(timeout, Timeout): + timeout = timeout.read + if timeout is not None: + headers["x-scalar-read-timeout"] = str(timeout) + + return headers + + def _prepare_url(self, url: str) -> URL: + """ + Merge a URL argument together with any 'base_url' on the client, + to create the URL used for the outgoing request. + """ + # Copied from httpx's `_merge_url` method. + merge_url = URL(url) + if merge_url.is_relative_url: + merge_raw_path = self.base_url.raw_path + merge_url.raw_path.lstrip(b"/") + return self.base_url.copy_with(raw_path=merge_raw_path) + + return merge_url + + def _make_sse_decoder(self) -> SSEDecoder | SSEBytesDecoder: + return SSEDecoder() + + def _build_request( + self, + options: FinalRequestOptions, + *, + retries_taken: int = 0, + ) -> httpx.Request: + if log.isEnabledFor(logging.DEBUG): + log.debug( + "Request options: %s", + model_dump( + options, + exclude_unset=True, + # Pydantic v1 can't dump every type we support in content, so we exclude it for now. + exclude={ + "content", + } + if PYDANTIC_V1 + else {}, + ), + ) + kwargs: dict[str, Any] = {} + + json_data = options.json_data + if options.extra_json is not None: + if json_data is None: + json_data = cast(Body, options.extra_json) + elif is_mapping(json_data): + json_data = _merge_mappings(json_data, options.extra_json) + else: + raise RuntimeError(f"Unexpected JSON data type, {type(json_data)}, cannot merge with `extra_body`") + + params = _merge_mappings({**self._auth_query(options.security), **self.default_query}, options.params) + cookies = self._auth_cookies(options.security) + headers = self._build_headers(options, retries_taken=retries_taken, params=params, cookies=cookies) + content_type = headers.get("Content-Type") + files = options.files + + # If the given Content-Type header is multipart/form-data then it + # has to be removed so that httpx can generate the header with + # additional information for us as it has to be in this form + # for the server to be able to correctly parse the request: + # multipart/form-data; boundary=---abc-- + if content_type is not None and content_type.startswith("multipart/form-data"): + if "boundary" not in content_type: + # only remove the header if the boundary hasn't been explicitly set + # as the caller doesn't want httpx to come up with their own boundary + headers.pop("Content-Type") + + # As we are now sending multipart/form-data instead of application/json + # we need to tell httpx to use it, https://www.python-httpx.org/advanced/clients/#multipart-file-encoding + if json_data: + if not is_dict(json_data): + raise TypeError( + f"Expected query input to be a dictionary for multipart requests but got {type(json_data)} instead." + ) + kwargs["data"] = self._serialize_multipartform(json_data) + + # httpx determines whether or not to send a "multipart/form-data" + # request based on the truthiness of the "files" argument. + # This gets around that issue by generating a dict value that + # evaluates to true. + # + # https://github.com/encode/httpx/discussions/2399#discussioncomment-3814186 + if not files: + files = cast(HttpxRequestFiles, ForceMultipartDict()) + + prepared_url = self._prepare_url(options.url) + # preserve hard-coded query params from the url + if params and prepared_url.query: + params = {**dict(prepared_url.params.items()), **params} + prepared_url = prepared_url.copy_with(raw_path=prepared_url.raw_path.split(b"?", 1)[0]) + if "_" in prepared_url.host: + # work around https://github.com/encode/httpx/discussions/2880 + kwargs["extensions"] = {"sni_hostname": prepared_url.host.replace("_", "-")} + + is_body_allowed = options.method.lower() != "get" + + if is_body_allowed: + if options.content is not None and json_data is not None: + raise TypeError("Passing both `content` and `json_data` is not supported") + if options.content is not None and files is not None: + raise TypeError("Passing both `content` and `files` is not supported") + if options.content is not None: + kwargs["content"] = options.content + elif isinstance(json_data, bytes): + kwargs["content"] = json_data + elif not files: + # Don't set content when JSON is sent as multipart/form-data, + # since httpx's content param overrides other body arguments + kwargs["content"] = openapi_dumps(json_data) if is_given(json_data) and json_data is not None else None + kwargs["files"] = files + else: + headers.pop("Content-Type", None) + kwargs.pop("data", None) + + # TODO: report this error to httpx + return self._client.build_request( # pyright: ignore[reportUnknownMemberType] + headers=headers, + timeout=self.timeout if isinstance(options.timeout, NotGiven) else options.timeout, + method=options.method, + url=prepared_url, + # the `Query` type that we use is incompatible with qs' + # `Params` type as it needs to be typed as `Mapping[str, object]` + # so that passing a `TypedDict` doesn't cause an error. + # https://github.com/microsoft/pyright/issues/3526#event-6715453066 + params=self.qs.stringify(cast(Mapping[str, Any], params)) if params else None, + cookies=cookies or None, + **kwargs, + ) + + def _serialize_multipartform(self, data: Mapping[object, object]) -> dict[str, object]: + items = self.qs.stringify_items( + # TODO: type ignore is required as stringify_items is well typed but we can't be + # well typed without heavy validation. + data, # type: ignore + array_format="brackets", + ) + serialized: dict[str, object] = {} + for key, value in items: + existing = serialized.get(key) + + if not existing: + serialized[key] = value + continue + + # If a value has already been set for this key then that + # means we're sending data like `array[]=[1, 2, 3]` and we + # need to tell httpx that we want to send multiple values with + # the same key which is done by using a list or a tuple. + # + # Note: 2d arrays should never result in the same key at both + # levels so it's safe to assume that if the value is a list, + # it was because we changed it to be a list. + if is_list(existing): + existing.append(value) + else: + serialized[key] = [existing, value] + + return serialized + + def _maybe_override_cast_to(self, cast_to: type[ResponseT], options: FinalRequestOptions) -> type[ResponseT]: + if not is_given(options.headers): + return cast_to + + # make a copy of the headers so we don't mutate user-input + headers = dict(options.headers) + + # we internally support defining a temporary header to override the + # default `cast_to` type for use with `.with_raw_response` and `.with_streaming_response` + # see _response.py for implementation details + override_cast_to = headers.pop(OVERRIDE_CAST_TO_HEADER, not_given) + if is_given(override_cast_to): + options.headers = headers + return cast(Type[ResponseT], override_cast_to) + + return cast_to + + def _should_stream_response_body(self, request: httpx.Request) -> bool: + return request.headers.get(RAW_RESPONSE_HEADER) == "stream" # type: ignore[no-any-return] + + def _process_response_data( + self, + *, + data: object, + cast_to: type[ResponseT], + response: httpx.Response, + ) -> ResponseT: + if data is None: + return cast(ResponseT, None) + + if cast_to is object: + return cast(ResponseT, data) + + try: + if inspect.isclass(cast_to) and issubclass(cast_to, ModelBuilderProtocol): + return cast(ResponseT, cast_to.build(response=response, data=data)) + + if self._strict_response_validation: + return cast(ResponseT, validate_type(type_=cast_to, value=data)) + + return cast(ResponseT, construct_type(type_=cast_to, value=data)) + except pydantic.ValidationError as err: + raise APIResponseValidationError(response=response, body=data) from err + + @property + def qs(self) -> Querystring: + return Querystring() + + @property + def custom_auth(self) -> httpx.Auth | None: + return None + + @property + def auth_headers(self) -> dict[str, str]: + return {} + + @property + def default_headers(self) -> dict[str, str | Omit]: + return { + "Accept": "application/json", + "Content-Type": "application/json", + "User-Agent": self.user_agent, + **self.platform_headers(), + **self._custom_headers, + } + + @property + def default_query(self) -> dict[str, object]: + return { + **self._custom_query, + } + + def _validate_headers( + self, + headers: Headers, # noqa: ARG002 + custom_headers: Headers, # noqa: ARG002 + params: Query, # noqa: ARG002 + cookies: Mapping[str, str], # noqa: ARG002 + ) -> None: + """Validate merged auth-bearing headers, query params, and cookies. + + Does nothing by default. + """ + return + + @property + def user_agent(self) -> str: + return f"{self.__class__.__name__}/Python {self._version}" + + @property + def base_url(self) -> URL: + return self._base_url + + @base_url.setter + def base_url(self, url: URL | str) -> None: + self._base_url = self._enforce_trailing_slash(url if isinstance(url, URL) else URL(url)) + + def platform_headers(self) -> Dict[str, str]: + # the actual implementation is in a separate `lru_cache` decorated + # function because adding `lru_cache` to methods will leak memory + # https://github.com/python/cpython/issues/88476 + return platform_headers(self._version, platform=self._platform) + + def _parse_retry_after_header(self, response_headers: Optional[httpx.Headers] = None) -> float | None: + """Returns a float of the number of seconds (not milliseconds) to wait after retrying, or None if unspecified. + + About the Retry-After header: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Retry-After + See also https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Retry-After#syntax + """ + if response_headers is None: + return None + + # First, try the non-standard `retry-after-ms` header for milliseconds, + # which is more precise than integer-seconds `retry-after` + try: + retry_ms_header = response_headers.get("retry-after-ms", None) + return float(retry_ms_header) / 1000 + except (TypeError, ValueError): + pass + + # Next, try parsing `retry-after` header as seconds (allowing nonstandard floats). + retry_header = response_headers.get("retry-after") + try: + # note: the spec indicates that this should only ever be an integer + # but if someone sends a float there's no reason for us to not respect it + return float(retry_header) + except (TypeError, ValueError): + pass + + # Last, try parsing `retry-after` as a date. + retry_date_tuple = email.utils.parsedate_tz(retry_header) + if retry_date_tuple is None: + return None + + retry_date = email.utils.mktime_tz(retry_date_tuple) + return float(retry_date - time.time()) + + def _calculate_retry_timeout( + self, + remaining_retries: int, + options: FinalRequestOptions, + response_headers: Optional[httpx.Headers] = None, + ) -> float: + max_retries = options.get_max_retries(self.max_retries) + + # If the API asks us to wait a certain amount of time (and it's a reasonable amount), just do what it says. + retry_after = self._parse_retry_after_header(response_headers) + if retry_after is not None and 0 < retry_after <= 60: + return retry_after + + # Also cap retry count to 1000 to avoid any potential overflows with `pow` + nb_retries = min(max_retries - remaining_retries, 1000) + + # Apply exponential backoff, but not more than the max. + sleep_seconds = min(INITIAL_RETRY_DELAY * pow(2.0, nb_retries), MAX_RETRY_DELAY) + + # Apply some jitter, plus-or-minus half a second. + jitter = 1 - 0.25 * random() + timeout = sleep_seconds * jitter + return timeout if timeout >= 0 else 0 + + def _should_retry(self, response: httpx.Response) -> bool: + # Note: this is not a standard header + should_retry_header = response.headers.get("x-should-retry") + + # If the server explicitly says whether or not to retry, obey. + if should_retry_header == "true": + log.debug("Retrying as header `x-should-retry` is set to `true`") + return True + if should_retry_header == "false": + log.debug("Not retrying as header `x-should-retry` is set to `false`") + return False + + # Retry on request timeouts. + if response.status_code == 408: + log.debug("Retrying due to status code %i", response.status_code) + return True + + # Retry on lock timeouts. + if response.status_code == 409: + log.debug("Retrying due to status code %i", response.status_code) + return True + + # Retry on rate limits. + if response.status_code == 429: + log.debug("Retrying due to status code %i", response.status_code) + return True + + # Retry internal errors. + if response.status_code >= 500: + log.debug("Retrying due to status code %i", response.status_code) + return True + + log.debug("Not retrying") + return False + + def _idempotency_key(self) -> str: + return f"scalar-python-retry-{uuid.uuid4()}" + + +class _DefaultHttpxClient(httpx.Client): + def __init__(self, **kwargs: Any) -> None: + kwargs.setdefault("timeout", DEFAULT_TIMEOUT) + kwargs.setdefault("limits", DEFAULT_CONNECTION_LIMITS) + kwargs.setdefault("follow_redirects", True) + super().__init__(**kwargs) + + +if TYPE_CHECKING: + DefaultHttpxClient = httpx.Client + """An alias to `httpx.Client` that provides the same defaults that this SDK + uses internally. + + This is useful because overriding the `http_client` with your own instance of + `httpx.Client` will result in httpx's defaults being used, not ours. + """ +else: + DefaultHttpxClient = _DefaultHttpxClient + + +class SyncHttpxClientWrapper(DefaultHttpxClient): + def __del__(self) -> None: + if self.is_closed: + return + + try: + self.close() + except Exception: + pass + + +class SyncAPIClient(BaseClient[httpx.Client, Stream[Any]]): + _client: httpx.Client + _default_stream_cls: type[Stream[Any]] | None = None + + def __init__( + self, + *, + version: str, + base_url: str | URL, + max_retries: int = DEFAULT_MAX_RETRIES, + timeout: float | Timeout | None | NotGiven = not_given, + http_client: httpx.Client | None = None, + custom_headers: Mapping[str, str] | None = None, + custom_query: Mapping[str, object] | None = None, + _strict_response_validation: bool, + **kwargs: Any, + ) -> None: + if not is_given(timeout): + # if the user passed in a custom http client with a non-default + # timeout set then we use that timeout. + # + # note: there is an edge case here where the user passes in a client + # where they've explicitly set the timeout to match the default timeout + # as this check is structural, meaning that we'll think they didn't + # pass in a timeout and will ignore it + if http_client and http_client.timeout != HTTPX_DEFAULT_TIMEOUT: + timeout = http_client.timeout + else: + timeout = DEFAULT_TIMEOUT + + if http_client is not None and not isinstance(http_client, httpx.Client): # pyright: ignore[reportUnnecessaryIsInstance] + raise TypeError( + f"Invalid `http_client` argument; Expected an instance of `httpx.Client` but got {type(http_client)}" + ) + + super().__init__( + version=version, + # cast to a valid type because mypy doesn't understand our type narrowing + timeout=cast(Timeout, timeout), + base_url=base_url, + max_retries=max_retries, + custom_query=custom_query, + custom_headers=custom_headers, + _strict_response_validation=_strict_response_validation, + ) + self._client = http_client or SyncHttpxClientWrapper( + base_url=base_url, + # cast to a valid type because mypy doesn't understand our type narrowing + timeout=cast(Timeout, timeout), + # Used by generated `with_options(_extra_kwargs=...)` for HTTPX client configuration. + **kwargs, + ) + + def is_closed(self) -> bool: + return self._client.is_closed + + def close(self) -> None: + """Close the underlying HTTPX client. + + The client will *not* be usable after this. + """ + # If an error is thrown while constructing a client, self._client + # may not be present + if hasattr(self, "_client"): + self._client.close() + + def __enter__(self: _T) -> _T: + return self + + def __exit__( + self, + exc_type: type[BaseException] | None, + exc: BaseException | None, + exc_tb: TracebackType | None, + ) -> None: + self.close() + + def _prepare_options( + self, + options: FinalRequestOptions, # noqa: ARG002 + ) -> FinalRequestOptions: + """Hook for mutating the given options""" + return options + + def _prepare_request( + self, + request: httpx.Request, # noqa: ARG002 + ) -> None: + """This method is used as a callback for mutating the `Request` object + after it has been constructed. + This is useful for cases where you want to add certain headers based off of + the request properties, e.g. `url`, `method` etc. + """ + return None + + @overload + def request( + self, + cast_to: Type[ResponseT], + options: FinalRequestOptions, + *, + stream: Literal[True], + stream_cls: Type[_StreamT], + ) -> _StreamT: ... + + @overload + def request( + self, + cast_to: Type[ResponseT], + options: FinalRequestOptions, + *, + stream: Literal[False] = False, + ) -> ResponseT: ... + + @overload + def request( + self, + cast_to: Type[ResponseT], + options: FinalRequestOptions, + *, + stream: bool = False, + stream_cls: Type[_StreamT] | None = None, + ) -> ResponseT | _StreamT: ... + + def request( + self, + cast_to: Type[ResponseT], + options: FinalRequestOptions, + *, + stream: bool = False, + stream_cls: type[_StreamT] | None = None, + ) -> ResponseT | _StreamT: + cast_to = self._maybe_override_cast_to(cast_to, options) + + # create a copy of the options we were given so that if the + # options are mutated later & we then retry, the retries are + # given the original options + input_options = model_copy(options) + if input_options.idempotency_key is None and input_options.method.lower() != "get": + # ensure the idempotency key is reused between requests + input_options.idempotency_key = self._idempotency_key() + + response: httpx.Response | None = None + max_retries = input_options.get_max_retries(self.max_retries) + + retries_taken = 0 + for retries_taken in range(max_retries + 1): + options = model_copy(input_options) + options = self._prepare_options(options) + + remaining_retries = max_retries - retries_taken + request = self._build_request(options, retries_taken=retries_taken) + self._prepare_request(request) + + kwargs: HttpxSendArgs = {} + custom_auth = self._custom_auth(options.security) + if custom_auth is not None: + kwargs["auth"] = custom_auth + + if options.follow_redirects is not None: + kwargs["follow_redirects"] = options.follow_redirects + + log.debug("Sending HTTP Request: %s %s", request.method, request.url) + + response = None + try: + response = self._client.send( + request, + stream=stream or self._should_stream_response_body(request=request), + **kwargs, + ) + except httpx.TimeoutException as err: + log.debug("Encountered httpx.TimeoutException", exc_info=True) + + if remaining_retries > 0: + self._sleep_for_retry( + retries_taken=retries_taken, + max_retries=max_retries, + options=input_options, + response=None, + ) + continue + + log.debug("Raising timeout error") + raise APITimeoutError(request=request) from err + except Exception as err: + log.debug("Encountered Exception", exc_info=True) + + if remaining_retries > 0: + self._sleep_for_retry( + retries_taken=retries_taken, + max_retries=max_retries, + options=input_options, + response=None, + ) + continue + + log.debug("Raising connection error") + raise APIConnectionError(request=request) from err + + log.debug( + 'HTTP Response: %s %s "%i %s" %s', + request.method, + request.url, + response.status_code, + response.reason_phrase, + response.headers, + ) + + try: + response.raise_for_status() + except httpx.HTTPStatusError as err: # thrown on 4xx and 5xx status code + log.debug("Encountered httpx.HTTPStatusError", exc_info=True) + + if remaining_retries > 0 and self._should_retry(err.response): + err.response.close() + self._sleep_for_retry( + retries_taken=retries_taken, + max_retries=max_retries, + options=input_options, + response=response, + ) + continue + + # If the response is streamed then we need to explicitly read the response + # to completion before attempting to access the response text. + if not err.response.is_closed: + err.response.read() + + log.debug("Re-raising status error") + raise self._make_status_error_from_response(err.response) from None + + break + + assert response is not None, "could not resolve response (should never happen)" + return self._process_response( + cast_to=cast_to, + options=options, + response=response, + stream=stream, + stream_cls=stream_cls, + retries_taken=retries_taken, + ) + + def _sleep_for_retry( + self, *, retries_taken: int, max_retries: int, options: FinalRequestOptions, response: httpx.Response | None + ) -> None: + remaining_retries = max_retries - retries_taken + if remaining_retries == 1: + log.debug("1 retry left") + else: + log.debug("%i retries left", remaining_retries) + + timeout = self._calculate_retry_timeout(remaining_retries, options, response.headers if response else None) + log.info("Retrying request to %s in %f seconds", options.url, timeout) + + time.sleep(timeout) + + def _process_response( + self, + *, + cast_to: Type[ResponseT], + options: FinalRequestOptions, + response: httpx.Response, + stream: bool, + stream_cls: type[Stream[Any]] | type[AsyncStream[Any]] | None, + retries_taken: int = 0, + ) -> ResponseT: + origin = get_origin(cast_to) or cast_to + + if ( + inspect.isclass(origin) + and issubclass(origin, BaseAPIResponse) + # we only want to actually return the custom BaseAPIResponse class if we're + # returning the raw response, or if we're not streaming SSE, as if we're streaming + # SSE then `cast_to` doesn't actively reflect the type we need to parse into + and (not stream or bool(response.request.headers.get(RAW_RESPONSE_HEADER))) + ): + if not issubclass(origin, APIResponse): + raise TypeError(f"API Response types must subclass {APIResponse}; Received {origin}") + + response_cls = cast("type[BaseAPIResponse[Any]]", cast_to) + return cast( + ResponseT, + response_cls( + raw=response, + client=self, + cast_to=extract_response_type(response_cls), + stream=stream, + stream_cls=stream_cls, + options=options, + retries_taken=retries_taken, + ), + ) + + if cast_to == httpx.Response: + return cast(ResponseT, response) + + api_response = APIResponse( + raw=response, + client=self, + cast_to=cast("type[ResponseT]", cast_to), # pyright: ignore[reportUnnecessaryCast] + stream=stream, + stream_cls=stream_cls, + options=options, + retries_taken=retries_taken, + ) + if bool(response.request.headers.get(RAW_RESPONSE_HEADER)): + return cast(ResponseT, api_response) + + return api_response.parse() + + def _request_api_list( + self, + model: Type[object], + page: Type[SyncPageT], + options: FinalRequestOptions, + cursor_config: Optional[CursorPageConfig] = None, + ) -> SyncPageT: + def _parser(resp: SyncPageT) -> SyncPageT: + resp._set_private_attributes( + client=self, + model=model, + options=options, + cursor_config=cursor_config, + ) + return resp + + options.post_parser = _parser + + return self.request(page, options, stream=False) + + @overload + def get( + self, + path: str, + *, + cast_to: Type[ResponseT], + options: RequestOptions = {}, + stream: Literal[False] = False, + ) -> ResponseT: ... + + @overload + def get( + self, + path: str, + *, + cast_to: Type[ResponseT], + options: RequestOptions = {}, + stream: Literal[True], + stream_cls: type[_StreamT], + ) -> _StreamT: ... + + @overload + def get( + self, + path: str, + *, + cast_to: Type[ResponseT], + options: RequestOptions = {}, + stream: bool, + stream_cls: type[_StreamT] | None = None, + ) -> ResponseT | _StreamT: ... + + def get( + self, + path: str, + *, + cast_to: Type[ResponseT], + options: RequestOptions = {}, + stream: bool = False, + stream_cls: type[_StreamT] | None = None, + ) -> ResponseT | _StreamT: + opts = FinalRequestOptions.construct(method="get", url=path, **options) + # cast is required because mypy complains about returning Any even though + # it understands the type variables + return cast(ResponseT, self.request(cast_to, opts, stream=stream, stream_cls=stream_cls)) + + @overload + def post( + self, + path: str, + *, + cast_to: Type[ResponseT], + body: Body | None = None, + content: BinaryTypes | None = None, + options: RequestOptions = {}, + files: RequestFiles | None = None, + stream: Literal[False] = False, + ) -> ResponseT: ... + + @overload + def post( + self, + path: str, + *, + cast_to: Type[ResponseT], + body: Body | None = None, + content: BinaryTypes | None = None, + options: RequestOptions = {}, + files: RequestFiles | None = None, + stream: Literal[True], + stream_cls: type[_StreamT], + ) -> _StreamT: ... + + @overload + def post( + self, + path: str, + *, + cast_to: Type[ResponseT], + body: Body | None = None, + content: BinaryTypes | None = None, + options: RequestOptions = {}, + files: RequestFiles | None = None, + stream: bool, + stream_cls: type[_StreamT] | None = None, + ) -> ResponseT | _StreamT: ... + + def post( + self, + path: str, + *, + cast_to: Type[ResponseT], + body: Body | None = None, + content: BinaryTypes | None = None, + options: RequestOptions = {}, + files: RequestFiles | None = None, + stream: bool = False, + stream_cls: type[_StreamT] | None = None, + ) -> ResponseT | _StreamT: + if body is not None and content is not None: + raise TypeError("Passing both `body` and `content` is not supported") + if files is not None and content is not None: + raise TypeError("Passing both `files` and `content` is not supported") + if isinstance(body, bytes): + warnings.warn( + "Passing raw bytes as `body` is deprecated and will be removed in a future version. " + "Please pass raw bytes via the `content` parameter instead.", + DeprecationWarning, + stacklevel=2, + ) + opts = FinalRequestOptions.construct( + method="post", url=path, json_data=body, content=content, files=to_httpx_files(files), **options + ) + return cast(ResponseT, self.request(cast_to, opts, stream=stream, stream_cls=stream_cls)) + + def patch( + self, + path: str, + *, + cast_to: Type[ResponseT], + body: Body | None = None, + content: BinaryTypes | None = None, + files: RequestFiles | None = None, + options: RequestOptions = {}, + ) -> ResponseT: + if body is not None and content is not None: + raise TypeError("Passing both `body` and `content` is not supported") + if files is not None and content is not None: + raise TypeError("Passing both `files` and `content` is not supported") + if isinstance(body, bytes): + warnings.warn( + "Passing raw bytes as `body` is deprecated and will be removed in a future version. " + "Please pass raw bytes via the `content` parameter instead.", + DeprecationWarning, + stacklevel=2, + ) + opts = FinalRequestOptions.construct( + method="patch", url=path, json_data=body, content=content, files=to_httpx_files(files), **options + ) + return self.request(cast_to, opts) + + def put( + self, + path: str, + *, + cast_to: Type[ResponseT], + body: Body | None = None, + content: BinaryTypes | None = None, + files: RequestFiles | None = None, + options: RequestOptions = {}, + ) -> ResponseT: + if body is not None and content is not None: + raise TypeError("Passing both `body` and `content` is not supported") + if files is not None and content is not None: + raise TypeError("Passing both `files` and `content` is not supported") + if isinstance(body, bytes): + warnings.warn( + "Passing raw bytes as `body` is deprecated and will be removed in a future version. " + "Please pass raw bytes via the `content` parameter instead.", + DeprecationWarning, + stacklevel=2, + ) + opts = FinalRequestOptions.construct( + method="put", url=path, json_data=body, content=content, files=to_httpx_files(files), **options + ) + return self.request(cast_to, opts) + + def delete( + self, + path: str, + *, + cast_to: Type[ResponseT], + body: Body | None = None, + content: BinaryTypes | None = None, + options: RequestOptions = {}, + ) -> ResponseT: + if body is not None and content is not None: + raise TypeError("Passing both `body` and `content` is not supported") + if isinstance(body, bytes): + warnings.warn( + "Passing raw bytes as `body` is deprecated and will be removed in a future version. " + "Please pass raw bytes via the `content` parameter instead.", + DeprecationWarning, + stacklevel=2, + ) + opts = FinalRequestOptions.construct(method="delete", url=path, json_data=body, content=content, **options) + return self.request(cast_to, opts) + + def get_api_list( + self, + path: str, + *, + model: Type[object], + page: Type[SyncPageT], + body: Body | None = None, + options: RequestOptions = {}, + method: str = "get", + cursor_config: Optional[CursorPageConfig] = None, + ) -> SyncPageT: + opts = FinalRequestOptions.construct(method=method, url=path, json_data=body, **options) + return self._request_api_list(model, page, opts, cursor_config=cursor_config) + + +class _DefaultAsyncHttpxClient(httpx.AsyncClient): + def __init__(self, **kwargs: Any) -> None: + kwargs.setdefault("timeout", DEFAULT_TIMEOUT) + kwargs.setdefault("limits", DEFAULT_CONNECTION_LIMITS) + kwargs.setdefault("follow_redirects", True) + super().__init__(**kwargs) + + +try: + import httpx_aiohttp +except ImportError: + + class _DefaultAioHttpClient(httpx.AsyncClient): + def __init__(self, **_kwargs: Any) -> None: + raise RuntimeError("To use the aiohttp client you must have installed the package with the `aiohttp` extra") +else: + + class _DefaultAioHttpClient(httpx_aiohttp.HttpxAiohttpClient): # type: ignore + def __init__(self, **kwargs: Any) -> None: + kwargs.setdefault("timeout", DEFAULT_TIMEOUT) + kwargs.setdefault("limits", DEFAULT_CONNECTION_LIMITS) + kwargs.setdefault("follow_redirects", True) + + super().__init__(**kwargs) + + +if TYPE_CHECKING: + DefaultAsyncHttpxClient = httpx.AsyncClient + """An alias to `httpx.AsyncClient` that provides the same defaults that this SDK + uses internally. + + This is useful because overriding the `http_client` with your own instance of + `httpx.AsyncClient` will result in httpx's defaults being used, not ours. + """ + + DefaultAioHttpClient = httpx.AsyncClient + """An alias to `httpx.AsyncClient` that changes the default HTTP transport to `aiohttp`.""" +else: + DefaultAsyncHttpxClient = _DefaultAsyncHttpxClient + DefaultAioHttpClient = _DefaultAioHttpClient + + +class AsyncHttpxClientWrapper(DefaultAsyncHttpxClient): + def __del__(self) -> None: + if self.is_closed: + return + + try: + # TODO(someday): support non asyncio runtimes here + asyncio.get_running_loop().create_task(self.aclose()) + except Exception: + pass + + +class AsyncAPIClient(BaseClient[httpx.AsyncClient, AsyncStream[Any]]): + _client: httpx.AsyncClient + _default_stream_cls: type[AsyncStream[Any]] | None = None + + def __init__( + self, + *, + version: str, + base_url: str | URL, + _strict_response_validation: bool, + max_retries: int = DEFAULT_MAX_RETRIES, + timeout: float | Timeout | None | NotGiven = not_given, + http_client: httpx.AsyncClient | None = None, + custom_headers: Mapping[str, str] | None = None, + custom_query: Mapping[str, object] | None = None, + **kwargs: Any, + ) -> None: + if not is_given(timeout): + # if the user passed in a custom http client with a non-default + # timeout set then we use that timeout. + # + # note: there is an edge case here where the user passes in a client + # where they've explicitly set the timeout to match the default timeout + # as this check is structural, meaning that we'll think they didn't + # pass in a timeout and will ignore it + if http_client and http_client.timeout != HTTPX_DEFAULT_TIMEOUT: + timeout = http_client.timeout + else: + timeout = DEFAULT_TIMEOUT + + if http_client is not None and not isinstance(http_client, httpx.AsyncClient): # pyright: ignore[reportUnnecessaryIsInstance] + raise TypeError( + f"Invalid `http_client` argument; Expected an instance of `httpx.AsyncClient` but got {type(http_client)}" + ) + + super().__init__( + version=version, + base_url=base_url, + # cast to a valid type because mypy doesn't understand our type narrowing + timeout=cast(Timeout, timeout), + max_retries=max_retries, + custom_query=custom_query, + custom_headers=custom_headers, + _strict_response_validation=_strict_response_validation, + ) + self._client = http_client or AsyncHttpxClientWrapper( + base_url=base_url, + # cast to a valid type because mypy doesn't understand our type narrowing + timeout=cast(Timeout, timeout), + # Used by generated `with_options(_extra_kwargs=...)` for HTTPX client configuration. + **kwargs, + ) + + def is_closed(self) -> bool: + return self._client.is_closed + + async def close(self) -> None: + """Close the underlying HTTPX client. + + The client will *not* be usable after this. + """ + await self._client.aclose() + + async def __aenter__(self: _T) -> _T: + return self + + async def __aexit__( + self, + exc_type: type[BaseException] | None, + exc: BaseException | None, + exc_tb: TracebackType | None, + ) -> None: + await self.close() + + async def _prepare_options( + self, + options: FinalRequestOptions, # noqa: ARG002 + ) -> FinalRequestOptions: + """Hook for mutating the given options""" + return options + + async def _prepare_request( + self, + request: httpx.Request, # noqa: ARG002 + ) -> None: + """This method is used as a callback for mutating the `Request` object + after it has been constructed. + This is useful for cases where you want to add certain headers based off of + the request properties, e.g. `url`, `method` etc. + """ + return None + + @overload + async def request( + self, + cast_to: Type[ResponseT], + options: FinalRequestOptions, + *, + stream: Literal[False] = False, + ) -> ResponseT: ... + + @overload + async def request( + self, + cast_to: Type[ResponseT], + options: FinalRequestOptions, + *, + stream: Literal[True], + stream_cls: type[_AsyncStreamT], + ) -> _AsyncStreamT: ... + + @overload + async def request( + self, + cast_to: Type[ResponseT], + options: FinalRequestOptions, + *, + stream: bool, + stream_cls: type[_AsyncStreamT] | None = None, + ) -> ResponseT | _AsyncStreamT: ... + + async def request( + self, + cast_to: Type[ResponseT], + options: FinalRequestOptions, + *, + stream: bool = False, + stream_cls: type[_AsyncStreamT] | None = None, + ) -> ResponseT | _AsyncStreamT: + if self._platform is None: + # `get_platform` can make blocking IO calls so we + # execute it earlier while we are in an async context + self._platform = await asyncify(get_platform)() + + cast_to = self._maybe_override_cast_to(cast_to, options) + + # create a copy of the options we were given so that if the + # options are mutated later & we then retry, the retries are + # given the original options + input_options = model_copy(options) + if input_options.idempotency_key is None and input_options.method.lower() != "get": + # ensure the idempotency key is reused between requests + input_options.idempotency_key = self._idempotency_key() + + response: httpx.Response | None = None + max_retries = input_options.get_max_retries(self.max_retries) + + retries_taken = 0 + for retries_taken in range(max_retries + 1): + options = model_copy(input_options) + options = await self._prepare_options(options) + + remaining_retries = max_retries - retries_taken + request = self._build_request(options, retries_taken=retries_taken) + await self._prepare_request(request) + + kwargs: HttpxSendArgs = {} + if self.custom_auth is not None: + kwargs["auth"] = self.custom_auth + + if options.follow_redirects is not None: + kwargs["follow_redirects"] = options.follow_redirects + + log.debug("Sending HTTP Request: %s %s", request.method, request.url) + + response = None + try: + response = await self._client.send( + request, + stream=stream or self._should_stream_response_body(request=request), + **kwargs, + ) + except httpx.TimeoutException as err: + log.debug("Encountered httpx.TimeoutException", exc_info=True) + + if remaining_retries > 0: + await self._sleep_for_retry( + retries_taken=retries_taken, + max_retries=max_retries, + options=input_options, + response=None, + ) + continue + + log.debug("Raising timeout error") + raise APITimeoutError(request=request) from err + except Exception as err: + log.debug("Encountered Exception", exc_info=True) + + if remaining_retries > 0: + await self._sleep_for_retry( + retries_taken=retries_taken, + max_retries=max_retries, + options=input_options, + response=None, + ) + continue + + log.debug("Raising connection error") + raise APIConnectionError(request=request) from err + + log.debug( + 'HTTP Response: %s %s "%i %s" %s', + request.method, + request.url, + response.status_code, + response.reason_phrase, + response.headers, + ) + + try: + response.raise_for_status() + except httpx.HTTPStatusError as err: # thrown on 4xx and 5xx status code + log.debug("Encountered httpx.HTTPStatusError", exc_info=True) + + if remaining_retries > 0 and self._should_retry(err.response): + await err.response.aclose() + await self._sleep_for_retry( + retries_taken=retries_taken, + max_retries=max_retries, + options=input_options, + response=response, + ) + continue + + # If the response is streamed then we need to explicitly read the response + # to completion before attempting to access the response text. + if not err.response.is_closed: + await err.response.aread() + + log.debug("Re-raising status error") + raise self._make_status_error_from_response(err.response) from None + + break + + assert response is not None, "could not resolve response (should never happen)" + return await self._process_response( + cast_to=cast_to, + options=options, + response=response, + stream=stream, + stream_cls=stream_cls, + retries_taken=retries_taken, + ) + + async def _sleep_for_retry( + self, *, retries_taken: int, max_retries: int, options: FinalRequestOptions, response: httpx.Response | None + ) -> None: + remaining_retries = max_retries - retries_taken + if remaining_retries == 1: + log.debug("1 retry left") + else: + log.debug("%i retries left", remaining_retries) + + timeout = self._calculate_retry_timeout(remaining_retries, options, response.headers if response else None) + log.info("Retrying request to %s in %f seconds", options.url, timeout) + + await anyio.sleep(timeout) + + async def _process_response( + self, + *, + cast_to: Type[ResponseT], + options: FinalRequestOptions, + response: httpx.Response, + stream: bool, + stream_cls: type[Stream[Any]] | type[AsyncStream[Any]] | None, + retries_taken: int = 0, + ) -> ResponseT: + origin = get_origin(cast_to) or cast_to + + if ( + inspect.isclass(origin) + and issubclass(origin, BaseAPIResponse) + # we only want to actually return the custom BaseAPIResponse class if we're + # returning the raw response, or if we're not streaming SSE, as if we're streaming + # SSE then `cast_to` doesn't actively reflect the type we need to parse into + and (not stream or bool(response.request.headers.get(RAW_RESPONSE_HEADER))) + ): + if not issubclass(origin, AsyncAPIResponse): + raise TypeError(f"API Response types must subclass {AsyncAPIResponse}; Received {origin}") + + response_cls = cast("type[BaseAPIResponse[Any]]", cast_to) + return cast( + "ResponseT", + response_cls( + raw=response, + client=self, + cast_to=extract_response_type(response_cls), + stream=stream, + stream_cls=stream_cls, + options=options, + retries_taken=retries_taken, + ), + ) + + if cast_to == httpx.Response: + return cast(ResponseT, response) + + api_response = AsyncAPIResponse( + raw=response, + client=self, + cast_to=cast("type[ResponseT]", cast_to), # pyright: ignore[reportUnnecessaryCast] + stream=stream, + stream_cls=stream_cls, + options=options, + retries_taken=retries_taken, + ) + if bool(response.request.headers.get(RAW_RESPONSE_HEADER)): + return cast(ResponseT, api_response) + + return await api_response.parse() + + def _request_api_list( + self, + model: Type[_T], + page: Type[AsyncPageT], + options: FinalRequestOptions, + cursor_config: Optional[CursorPageConfig] = None, + ) -> AsyncPaginator[_T, AsyncPageT]: + return AsyncPaginator( + client=self, options=options, page_cls=page, model=model, cursor_config=cursor_config + ) + + @overload + async def get( + self, + path: str, + *, + cast_to: Type[ResponseT], + options: RequestOptions = {}, + stream: Literal[False] = False, + ) -> ResponseT: ... + + @overload + async def get( + self, + path: str, + *, + cast_to: Type[ResponseT], + options: RequestOptions = {}, + stream: Literal[True], + stream_cls: type[_AsyncStreamT], + ) -> _AsyncStreamT: ... + + @overload + async def get( + self, + path: str, + *, + cast_to: Type[ResponseT], + options: RequestOptions = {}, + stream: bool, + stream_cls: type[_AsyncStreamT] | None = None, + ) -> ResponseT | _AsyncStreamT: ... + + async def get( + self, + path: str, + *, + cast_to: Type[ResponseT], + options: RequestOptions = {}, + stream: bool = False, + stream_cls: type[_AsyncStreamT] | None = None, + ) -> ResponseT | _AsyncStreamT: + opts = FinalRequestOptions.construct(method="get", url=path, **options) + return await self.request(cast_to, opts, stream=stream, stream_cls=stream_cls) + + @overload + async def post( + self, + path: str, + *, + cast_to: Type[ResponseT], + body: Body | None = None, + content: AsyncBinaryTypes | None = None, + files: RequestFiles | None = None, + options: RequestOptions = {}, + stream: Literal[False] = False, + ) -> ResponseT: ... + + @overload + async def post( + self, + path: str, + *, + cast_to: Type[ResponseT], + body: Body | None = None, + content: AsyncBinaryTypes | None = None, + files: RequestFiles | None = None, + options: RequestOptions = {}, + stream: Literal[True], + stream_cls: type[_AsyncStreamT], + ) -> _AsyncStreamT: ... + + @overload + async def post( + self, + path: str, + *, + cast_to: Type[ResponseT], + body: Body | None = None, + content: AsyncBinaryTypes | None = None, + files: RequestFiles | None = None, + options: RequestOptions = {}, + stream: bool, + stream_cls: type[_AsyncStreamT] | None = None, + ) -> ResponseT | _AsyncStreamT: ... + + async def post( + self, + path: str, + *, + cast_to: Type[ResponseT], + body: Body | None = None, + content: AsyncBinaryTypes | None = None, + files: RequestFiles | None = None, + options: RequestOptions = {}, + stream: bool = False, + stream_cls: type[_AsyncStreamT] | None = None, + ) -> ResponseT | _AsyncStreamT: + if body is not None and content is not None: + raise TypeError("Passing both `body` and `content` is not supported") + if files is not None and content is not None: + raise TypeError("Passing both `files` and `content` is not supported") + if isinstance(body, bytes): + warnings.warn( + "Passing raw bytes as `body` is deprecated and will be removed in a future version. " + "Please pass raw bytes via the `content` parameter instead.", + DeprecationWarning, + stacklevel=2, + ) + opts = FinalRequestOptions.construct( + method="post", url=path, json_data=body, content=content, files=await async_to_httpx_files(files), **options + ) + return await self.request(cast_to, opts, stream=stream, stream_cls=stream_cls) + + async def patch( + self, + path: str, + *, + cast_to: Type[ResponseT], + body: Body | None = None, + content: AsyncBinaryTypes | None = None, + files: RequestFiles | None = None, + options: RequestOptions = {}, + ) -> ResponseT: + if body is not None and content is not None: + raise TypeError("Passing both `body` and `content` is not supported") + if files is not None and content is not None: + raise TypeError("Passing both `files` and `content` is not supported") + if isinstance(body, bytes): + warnings.warn( + "Passing raw bytes as `body` is deprecated and will be removed in a future version. " + "Please pass raw bytes via the `content` parameter instead.", + DeprecationWarning, + stacklevel=2, + ) + opts = FinalRequestOptions.construct( + method="patch", + url=path, + json_data=body, + content=content, + files=await async_to_httpx_files(files), + **options, + ) + return await self.request(cast_to, opts) + + async def put( + self, + path: str, + *, + cast_to: Type[ResponseT], + body: Body | None = None, + content: AsyncBinaryTypes | None = None, + files: RequestFiles | None = None, + options: RequestOptions = {}, + ) -> ResponseT: + if body is not None and content is not None: + raise TypeError("Passing both `body` and `content` is not supported") + if files is not None and content is not None: + raise TypeError("Passing both `files` and `content` is not supported") + if isinstance(body, bytes): + warnings.warn( + "Passing raw bytes as `body` is deprecated and will be removed in a future version. " + "Please pass raw bytes via the `content` parameter instead.", + DeprecationWarning, + stacklevel=2, + ) + opts = FinalRequestOptions.construct( + method="put", url=path, json_data=body, content=content, files=await async_to_httpx_files(files), **options + ) + return await self.request(cast_to, opts) + + async def delete( + self, + path: str, + *, + cast_to: Type[ResponseT], + body: Body | None = None, + content: AsyncBinaryTypes | None = None, + options: RequestOptions = {}, + ) -> ResponseT: + if body is not None and content is not None: + raise TypeError("Passing both `body` and `content` is not supported") + if isinstance(body, bytes): + warnings.warn( + "Passing raw bytes as `body` is deprecated and will be removed in a future version. " + "Please pass raw bytes via the `content` parameter instead.", + DeprecationWarning, + stacklevel=2, + ) + opts = FinalRequestOptions.construct(method="delete", url=path, json_data=body, content=content, **options) + return await self.request(cast_to, opts) + + def get_api_list( + self, + path: str, + *, + model: Type[_T], + page: Type[AsyncPageT], + body: Body | None = None, + options: RequestOptions = {}, + method: str = "get", + cursor_config: Optional[CursorPageConfig] = None, + ) -> AsyncPaginator[_T, AsyncPageT]: + opts = FinalRequestOptions.construct(method=method, url=path, json_data=body, **options) + return self._request_api_list(model, page, opts, cursor_config=cursor_config) + + +def make_request_options( + *, + query: Query | None = None, + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + idempotency_key: str | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + post_parser: PostParser | NotGiven = not_given, + security: SecurityOptions | None = None, +) -> RequestOptions: + """Create a dict of type RequestOptions without keys of NotGiven values.""" + options: RequestOptions = {} + if extra_headers is not None: + options["headers"] = extra_headers + + if extra_body is not None: + options["extra_json"] = cast(AnyMapping, extra_body) + + if query is not None: + options["params"] = query + + if extra_query is not None: + options["params"] = {**options.get("params", {}), **extra_query} + + if not isinstance(timeout, NotGiven): + options["timeout"] = timeout + + if idempotency_key is not None: + options["idempotency_key"] = idempotency_key + + if is_given(post_parser): + # internal + options["post_parser"] = post_parser # type: ignore + + if security is not None: + options["security"] = security + + return options + + +class ForceMultipartDict(Dict[str, None]): + def __bool__(self) -> bool: + return True + + +class OtherPlatform: + def __init__(self, name: str) -> None: + self.name = name + + @override + def __str__(self) -> str: + return f"Other:{self.name}" + + +Platform = Union[ + OtherPlatform, + Literal[ + "MacOS", + "Linux", + "Windows", + "FreeBSD", + "OpenBSD", + "iOS", + "Android", + "Unknown", + ], +] + + +def get_platform() -> Platform: + try: + system = platform.system().lower() + platform_name = platform.platform().lower() + except Exception: + return "Unknown" + + if "iphone" in platform_name or "ipad" in platform_name: + # Tested using Python3IDE on an iPhone 11 and Pythonista on an iPad 7 + # system is Darwin and platform_name is a string like: + # - Darwin-21.6.0-iPhone12,1-64bit + # - Darwin-21.6.0-iPad7,11-64bit + return "iOS" + + if system == "darwin": + return "MacOS" + + if system == "windows": + return "Windows" + + if "android" in platform_name: + # Tested using Pydroid 3 + # system is Linux and platform_name is a string like 'Linux-5.10.81-android12-9-00001-geba40aecb3b7-ab8534902-aarch64-with-libc' + return "Android" + + if system == "linux": + # https://distro.readthedocs.io/en/latest/#distro.id + distro_id = distro.id() + if distro_id == "freebsd": + return "FreeBSD" + + if distro_id == "openbsd": + return "OpenBSD" + + return "Linux" + + if platform_name: + return OtherPlatform(platform_name) + + return "Unknown" + + +@lru_cache(maxsize=None) +def platform_headers(version: str, *, platform: Platform | None) -> Dict[str, str]: + return { + "X-Scalar-Lang": "python", + "X-Scalar-Package-Version": version, + "X-Scalar-OS": str(platform or get_platform()), + "X-Scalar-Arch": str(get_architecture()), + "X-Scalar-Runtime": get_python_runtime(), + "X-Scalar-Runtime-Version": get_python_version(), + } + + +class OtherArch: + def __init__(self, name: str) -> None: + self.name = name + + @override + def __str__(self) -> str: + return f"other:{self.name}" + + +Arch = Union[OtherArch, Literal["x32", "x64", "arm", "arm64", "unknown"]] + + +def get_python_runtime() -> str: + try: + return platform.python_implementation() + except Exception: + return "unknown" + + +def get_python_version() -> str: + try: + return platform.python_version() + except Exception: + return "unknown" + + +def get_architecture() -> Arch: + try: + machine = platform.machine().lower() + except Exception: + return "unknown" + + if machine in ("arm64", "aarch64"): + return "arm64" + + # TODO: untested + if machine == "arm": + return "arm" + + if machine == "x86_64": + return "x64" + + # TODO: untested + if sys.maxsize <= 2**32: + return "x32" + + if machine: + return OtherArch(machine) + + return "unknown" + + +def _merge_mappings( + obj1: Mapping[_T_co, Union[_T, Omit]], + obj2: Mapping[_T_co, Union[_T, Omit]], +) -> Dict[_T_co, _T]: + """Merge two mappings of the same type, removing any values that are instances of `Omit`. + + In cases with duplicate keys the second mapping takes precedence. + """ + merged = {**obj1, **obj2} + return {key: value for key, value in merged.items() if not isinstance(value, Omit)} diff --git a/src/_client.py b/src/_client.py new file mode 100644 index 0000000..7097de1 --- /dev/null +++ b/src/_client.py @@ -0,0 +1,794 @@ +# File generated from our OpenAPI spec by Scalar. See README.md for details. + +from __future__ import annotations + +import os +import threading +from typing import TYPE_CHECKING, Any, Mapping +from typing_extensions import Literal, Self, override + +import httpx + +from . import _exceptions +from ._qs import Querystring +from ._types import ( + Omit, + Headers, + Timeout, + NotGiven, + Transport, + ProxiesTypes, + RequestOptions, + not_given, +) +from ._utils import is_given, is_mapping_t, get_async_library +from ._compat import cached_property +from ._exceptions import APIStatusError +from ._base_client import ( + DEFAULT_MAX_RETRIES, + SyncAPIClient, + AsyncAPIClient, +) +from ._streaming import Stream as Stream, AsyncStream as AsyncStream +from ._version import __version__ + +if TYPE_CHECKING: + from .resources.registry import RegistryResource, AsyncRegistryResource + from .resources.schemas import SchemasResource, AsyncSchemasResource + from .resources.login_portals import LoginPortalsResource, AsyncLoginPortalsResource + from .resources.rules import RulesResource, AsyncRulesResource + from .resources.themes import ThemesResource, AsyncThemesResource + from .resources.teams import TeamsResource, AsyncTeamsResource + from .resources.scalar_docs import ScalarDocsResource, AsyncScalarDocsResource + from .resources.namespaces import NamespacesResource, AsyncNamespacesResource + from .resources.authentication import AuthenticationResource, AsyncAuthenticationResource + +# Serializes lazy resource imports so concurrent cold access from multiple +# threads cannot deadlock on CPython import locks (see CPython 3.14). +_RESOURCE_IMPORT_LOCK = threading.RLock() + +ENVIRONMENTS: dict[str, str] = { + "production": "https://access.scalar.com", + "local": "http://127.0.0.1:4010", +} + +__all__ = ["ENVIRONMENTS", "ScalarApi", "AsyncScalarApi", "Client", "AsyncClient", "Timeout", "Transport", "ProxiesTypes", "RequestOptions"] + + +class ScalarApi(SyncAPIClient): + # client options + bearer_auth: str | None + + def __init__( + self, + *, + bearer_auth: str | None = None, + environment: Literal["production", "local"] | NotGiven = not_given, + base_url: str | httpx.URL | None | NotGiven = not_given, + timeout: float | Timeout | None | NotGiven = not_given, + max_retries: int = DEFAULT_MAX_RETRIES, + default_headers: Mapping[str, str] | None = None, + default_query: Mapping[str, object] | None = None, + http_client: httpx.Client | None = None, + _strict_response_validation: bool = False, + **kwargs: Any, + ) -> None: + if bearer_auth is None: + bearer_auth = os.environ.get("BEARER_AUTH") + self.bearer_auth = bearer_auth + self._environment = environment + base_url_env = os.environ.get("SCALAR_BASE_URL") + if is_given(base_url) and base_url is not None: + if is_given(environment): + raise ValueError( + "Ambiguous URL; the `base_url` and `environment` arguments are both set. Pass `base_url=None` to use the environment.", + ) + elif is_given(environment): + if base_url_env and base_url is not None: + raise ValueError( + "Ambiguous URL; the base URL environment variable and the `environment` argument are both set. Pass base_url=None to use the environment.", + ) + try: + base_url = ENVIRONMENTS[environment] + except KeyError as exc: + raise ValueError(f"Unknown environment: {environment}") from exc + elif base_url_env is not None: + base_url = base_url_env + else: + self._environment = environment = "production" + try: + base_url = ENVIRONMENTS[environment] + except KeyError as exc: + raise ValueError(f"Unknown environment: {environment}") from exc + # Extra keyword args flow through `with_options(_extra_kwargs=...)` to the default HTTPX client. + super().__init__( + version=__version__, + base_url=base_url, + max_retries=max_retries, + timeout=timeout, + http_client=http_client, + custom_headers=default_headers, + custom_query=default_query, + _strict_response_validation=_strict_response_validation, + **kwargs, + ) + self._idempotency_header = "Idempotency-Key" + self._default_stream_cls = Stream + self._streaming_handlers: list[dict[str, object]] = [] + + @cached_property + def registry(self) -> "RegistryResource": + with _RESOURCE_IMPORT_LOCK: + from .resources.registry import RegistryResource + return RegistryResource(self) + + @cached_property + def schemas(self) -> "SchemasResource": + with _RESOURCE_IMPORT_LOCK: + from .resources.schemas import SchemasResource + return SchemasResource(self) + + @cached_property + def login_portals(self) -> "LoginPortalsResource": + with _RESOURCE_IMPORT_LOCK: + from .resources.login_portals import LoginPortalsResource + return LoginPortalsResource(self) + + @cached_property + def rules(self) -> "RulesResource": + with _RESOURCE_IMPORT_LOCK: + from .resources.rules import RulesResource + return RulesResource(self) + + @cached_property + def themes(self) -> "ThemesResource": + with _RESOURCE_IMPORT_LOCK: + from .resources.themes import ThemesResource + return ThemesResource(self) + + @cached_property + def teams(self) -> "TeamsResource": + with _RESOURCE_IMPORT_LOCK: + from .resources.teams import TeamsResource + return TeamsResource(self) + + @cached_property + def scalar_docs(self) -> "ScalarDocsResource": + with _RESOURCE_IMPORT_LOCK: + from .resources.scalar_docs import ScalarDocsResource + return ScalarDocsResource(self) + + @cached_property + def namespaces(self) -> "NamespacesResource": + with _RESOURCE_IMPORT_LOCK: + from .resources.namespaces import NamespacesResource + return NamespacesResource(self) + + @cached_property + def authentication(self) -> "AuthenticationResource": + with _RESOURCE_IMPORT_LOCK: + from .resources.authentication import AuthenticationResource + return AuthenticationResource(self) + + @cached_property + def with_raw_response(self) -> ScalarApiWithRawResponse: + return ScalarApiWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> ScalarApiWithStreamingResponse: + return ScalarApiWithStreamingResponse(self) + + def copy( + self, + *, + bearer_auth: str | None = None, + environment: str | None = None, + base_url: str | httpx.URL | None = None, + timeout: float | Timeout | None | NotGiven = not_given, + http_client: httpx.Client | None = None, + max_retries: int | NotGiven = not_given, + default_headers: Mapping[str, str] | None = None, + set_default_headers: Mapping[str, str] | None = None, + default_query: Mapping[str, object] | None = None, + set_default_query: Mapping[str, object] | None = None, + _extra_kwargs: Mapping[str, Any] | None = None, + ) -> Self: + """Create a new client reusing this client's options with optional overrides.""" + if default_headers is not None and set_default_headers is not None: + raise ValueError("The `default_headers` and `set_default_headers` arguments are mutually exclusive") + if default_query is not None and set_default_query is not None: + raise ValueError("The `default_query` and `set_default_query` arguments are mutually exclusive") + headers = self._custom_headers + if default_headers is not None: + headers = {**headers, **default_headers} + elif set_default_headers is not None: + headers = set_default_headers + params = self._custom_query + if default_query is not None: + params = {**params, **default_query} + elif set_default_query is not None: + params = set_default_query + http_client = http_client or self._client + copied_base_url = base_url if base_url is not None else self.base_url + # Environment overrides must resolve their own URL instead of reusing this client's host. + if environment is not None and base_url is None: + copied_base_url = None + return self.__class__( + bearer_auth=bearer_auth if bearer_auth is not None else self.bearer_auth, + environment=environment if environment is not None else self._environment, + base_url=copied_base_url, + timeout=self.timeout if isinstance(timeout, NotGiven) else timeout, + http_client=http_client, + max_retries=max_retries if is_given(max_retries) else self.max_retries, + default_headers=headers, + default_query=params, + _strict_response_validation=self._strict_response_validation, + **(_extra_kwargs or {}), + ) + + with_options = copy + + @property + @override + def qs(self) -> Querystring: + return Querystring(array_format="repeat") + + @override + def _auth_headers(self, security: dict[str, bool]) -> dict[str, str]: + _ = security + return { + **self._bearer_auth_header_auth, + } + + @override + def _auth_query(self, security: dict[str, bool]) -> dict[str, str]: + _ = security + return { + } + + @override + def _auth_cookies(self, security: dict[str, bool]) -> dict[str, str]: + _ = security + return { + } + + @property + def _bearer_auth_header_auth(self) -> dict[str, str]: + value = self.bearer_auth + if value is None: + return {} + return {"Authorization": f"Bearer {value}"} + + + @override + def _validate_headers( + self, + headers: Headers, + custom_headers: Headers, + params: Mapping[str, object], + cookies: Mapping[str, str], + ) -> None: + if headers.get("Authorization"): + return + if isinstance(custom_headers.get("Authorization"), Omit): + return + raise TypeError("Could not resolve authentication method. Expected Authorization to be set.") + + @property + @override + def default_headers(self) -> dict[str, str | Omit]: + return { + **super().default_headers, + "X-Scalar-Async": "false", + **self._custom_headers, + } + + @override + def _make_status_error(self, err_msg: str, *, body: object, response: httpx.Response) -> APIStatusError: + if response.status_code == 400: + return _exceptions.BadRequestError(err_msg, response=response, body=body) + if response.status_code == 401: + return _exceptions.AuthenticationError(err_msg, response=response, body=body) + if response.status_code == 403: + return _exceptions.PermissionDeniedError(err_msg, response=response, body=body) + if response.status_code == 404: + return _exceptions.NotFoundError(err_msg, response=response, body=body) + if response.status_code == 409: + return _exceptions.ConflictError(err_msg, response=response, body=body) + if response.status_code == 422: + return _exceptions.UnprocessableEntityError(err_msg, response=response, body=body) + if response.status_code == 429: + return _exceptions.RateLimitError(err_msg, response=response, body=body) + if response.status_code >= 500: + return _exceptions.InternalServerError(err_msg, response=response, body=body) + return APIStatusError(err_msg, response=response, body=body) + + +class AsyncScalarApi(AsyncAPIClient): + # client options + bearer_auth: str | None + + def __init__( + self, + *, + bearer_auth: str | None = None, + environment: Literal["production", "local"] | NotGiven = not_given, + base_url: str | httpx.URL | None | NotGiven = not_given, + timeout: float | Timeout | None | NotGiven = not_given, + max_retries: int = DEFAULT_MAX_RETRIES, + default_headers: Mapping[str, str] | None = None, + default_query: Mapping[str, object] | None = None, + http_client: httpx.AsyncClient | None = None, + _strict_response_validation: bool = False, + **kwargs: Any, + ) -> None: + if bearer_auth is None: + bearer_auth = os.environ.get("BEARER_AUTH") + self.bearer_auth = bearer_auth + self._environment = environment + base_url_env = os.environ.get("SCALAR_BASE_URL") + if is_given(base_url) and base_url is not None: + if is_given(environment): + raise ValueError( + "Ambiguous URL; the `base_url` and `environment` arguments are both set. Pass `base_url=None` to use the environment.", + ) + elif is_given(environment): + if base_url_env and base_url is not None: + raise ValueError( + "Ambiguous URL; the base URL environment variable and the `environment` argument are both set. Pass base_url=None to use the environment.", + ) + try: + base_url = ENVIRONMENTS[environment] + except KeyError as exc: + raise ValueError(f"Unknown environment: {environment}") from exc + elif base_url_env is not None: + base_url = base_url_env + else: + self._environment = environment = "production" + try: + base_url = ENVIRONMENTS[environment] + except KeyError as exc: + raise ValueError(f"Unknown environment: {environment}") from exc + # Extra keyword args flow through `with_options(_extra_kwargs=...)` to the default HTTPX client. + super().__init__( + version=__version__, + base_url=base_url, + max_retries=max_retries, + timeout=timeout, + http_client=http_client, + custom_headers=default_headers, + custom_query=default_query, + _strict_response_validation=_strict_response_validation, + **kwargs, + ) + self._idempotency_header = "Idempotency-Key" + self._default_stream_cls = AsyncStream + self._streaming_handlers: list[dict[str, object]] = [] + + @cached_property + def registry(self) -> "AsyncRegistryResource": + with _RESOURCE_IMPORT_LOCK: + from .resources.registry import AsyncRegistryResource + return AsyncRegistryResource(self) + + @cached_property + def schemas(self) -> "AsyncSchemasResource": + with _RESOURCE_IMPORT_LOCK: + from .resources.schemas import AsyncSchemasResource + return AsyncSchemasResource(self) + + @cached_property + def login_portals(self) -> "AsyncLoginPortalsResource": + with _RESOURCE_IMPORT_LOCK: + from .resources.login_portals import AsyncLoginPortalsResource + return AsyncLoginPortalsResource(self) + + @cached_property + def rules(self) -> "AsyncRulesResource": + with _RESOURCE_IMPORT_LOCK: + from .resources.rules import AsyncRulesResource + return AsyncRulesResource(self) + + @cached_property + def themes(self) -> "AsyncThemesResource": + with _RESOURCE_IMPORT_LOCK: + from .resources.themes import AsyncThemesResource + return AsyncThemesResource(self) + + @cached_property + def teams(self) -> "AsyncTeamsResource": + with _RESOURCE_IMPORT_LOCK: + from .resources.teams import AsyncTeamsResource + return AsyncTeamsResource(self) + + @cached_property + def scalar_docs(self) -> "AsyncScalarDocsResource": + with _RESOURCE_IMPORT_LOCK: + from .resources.scalar_docs import AsyncScalarDocsResource + return AsyncScalarDocsResource(self) + + @cached_property + def namespaces(self) -> "AsyncNamespacesResource": + with _RESOURCE_IMPORT_LOCK: + from .resources.namespaces import AsyncNamespacesResource + return AsyncNamespacesResource(self) + + @cached_property + def authentication(self) -> "AsyncAuthenticationResource": + with _RESOURCE_IMPORT_LOCK: + from .resources.authentication import AsyncAuthenticationResource + return AsyncAuthenticationResource(self) + + @cached_property + def with_raw_response(self) -> AsyncScalarApiWithRawResponse: + return AsyncScalarApiWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncScalarApiWithStreamingResponse: + return AsyncScalarApiWithStreamingResponse(self) + + def copy( + self, + *, + bearer_auth: str | None = None, + environment: str | None = None, + base_url: str | httpx.URL | None = None, + timeout: float | Timeout | None | NotGiven = not_given, + http_client: httpx.AsyncClient | None = None, + max_retries: int | NotGiven = not_given, + default_headers: Mapping[str, str] | None = None, + set_default_headers: Mapping[str, str] | None = None, + default_query: Mapping[str, object] | None = None, + set_default_query: Mapping[str, object] | None = None, + _extra_kwargs: Mapping[str, Any] | None = None, + ) -> Self: + """Create a new client reusing this client's options with optional overrides.""" + if default_headers is not None and set_default_headers is not None: + raise ValueError("The `default_headers` and `set_default_headers` arguments are mutually exclusive") + if default_query is not None and set_default_query is not None: + raise ValueError("The `default_query` and `set_default_query` arguments are mutually exclusive") + headers = self._custom_headers + if default_headers is not None: + headers = {**headers, **default_headers} + elif set_default_headers is not None: + headers = set_default_headers + params = self._custom_query + if default_query is not None: + params = {**params, **default_query} + elif set_default_query is not None: + params = set_default_query + http_client = http_client or self._client + copied_base_url = base_url if base_url is not None else self.base_url + # Environment overrides must resolve their own URL instead of reusing this client's host. + if environment is not None and base_url is None: + copied_base_url = None + return self.__class__( + bearer_auth=bearer_auth if bearer_auth is not None else self.bearer_auth, + environment=environment if environment is not None else self._environment, + base_url=copied_base_url, + timeout=self.timeout if isinstance(timeout, NotGiven) else timeout, + http_client=http_client, + max_retries=max_retries if is_given(max_retries) else self.max_retries, + default_headers=headers, + default_query=params, + _strict_response_validation=self._strict_response_validation, + **(_extra_kwargs or {}), + ) + + with_options = copy + + @property + @override + def qs(self) -> Querystring: + return Querystring(array_format="repeat") + + @override + def _auth_headers(self, security: dict[str, bool]) -> dict[str, str]: + _ = security + return { + **self._bearer_auth_header_auth, + } + + @override + def _auth_query(self, security: dict[str, bool]) -> dict[str, str]: + _ = security + return { + } + + @override + def _auth_cookies(self, security: dict[str, bool]) -> dict[str, str]: + _ = security + return { + } + + @property + def _bearer_auth_header_auth(self) -> dict[str, str]: + value = self.bearer_auth + if value is None: + return {} + return {"Authorization": f"Bearer {value}"} + + + @override + def _validate_headers( + self, + headers: Headers, + custom_headers: Headers, + params: Mapping[str, object], + cookies: Mapping[str, str], + ) -> None: + if headers.get("Authorization"): + return + if isinstance(custom_headers.get("Authorization"), Omit): + return + raise TypeError("Could not resolve authentication method. Expected Authorization to be set.") + + @property + @override + def default_headers(self) -> dict[str, str | Omit]: + return { + **super().default_headers, + "X-Scalar-Async": f"async:{get_async_library()}", + **self._custom_headers, + } + + @override + def _make_status_error(self, err_msg: str, *, body: object, response: httpx.Response) -> APIStatusError: + if response.status_code == 400: + return _exceptions.BadRequestError(err_msg, response=response, body=body) + if response.status_code == 401: + return _exceptions.AuthenticationError(err_msg, response=response, body=body) + if response.status_code == 403: + return _exceptions.PermissionDeniedError(err_msg, response=response, body=body) + if response.status_code == 404: + return _exceptions.NotFoundError(err_msg, response=response, body=body) + if response.status_code == 409: + return _exceptions.ConflictError(err_msg, response=response, body=body) + if response.status_code == 422: + return _exceptions.UnprocessableEntityError(err_msg, response=response, body=body) + if response.status_code == 429: + return _exceptions.RateLimitError(err_msg, response=response, body=body) + if response.status_code >= 500: + return _exceptions.InternalServerError(err_msg, response=response, body=body) + return APIStatusError(err_msg, response=response, body=body) + + +class ScalarApiWithRawResponse: + def __init__(self, client: ScalarApi) -> None: + self._client = client + + @cached_property + def registry(self) -> "RegistryResourceWithRawResponse": + with _RESOURCE_IMPORT_LOCK: + from .resources.registry import RegistryResourceWithRawResponse + return RegistryResourceWithRawResponse(self._client.registry) + + @cached_property + def schemas(self) -> "SchemasResourceWithRawResponse": + with _RESOURCE_IMPORT_LOCK: + from .resources.schemas import SchemasResourceWithRawResponse + return SchemasResourceWithRawResponse(self._client.schemas) + + @cached_property + def login_portals(self) -> "LoginPortalsResourceWithRawResponse": + with _RESOURCE_IMPORT_LOCK: + from .resources.login_portals import LoginPortalsResourceWithRawResponse + return LoginPortalsResourceWithRawResponse(self._client.login_portals) + + @cached_property + def rules(self) -> "RulesResourceWithRawResponse": + with _RESOURCE_IMPORT_LOCK: + from .resources.rules import RulesResourceWithRawResponse + return RulesResourceWithRawResponse(self._client.rules) + + @cached_property + def themes(self) -> "ThemesResourceWithRawResponse": + with _RESOURCE_IMPORT_LOCK: + from .resources.themes import ThemesResourceWithRawResponse + return ThemesResourceWithRawResponse(self._client.themes) + + @cached_property + def teams(self) -> "TeamsResourceWithRawResponse": + with _RESOURCE_IMPORT_LOCK: + from .resources.teams import TeamsResourceWithRawResponse + return TeamsResourceWithRawResponse(self._client.teams) + + @cached_property + def scalar_docs(self) -> "ScalarDocsResourceWithRawResponse": + with _RESOURCE_IMPORT_LOCK: + from .resources.scalar_docs import ScalarDocsResourceWithRawResponse + return ScalarDocsResourceWithRawResponse(self._client.scalar_docs) + + @cached_property + def namespaces(self) -> "NamespacesResourceWithRawResponse": + with _RESOURCE_IMPORT_LOCK: + from .resources.namespaces import NamespacesResourceWithRawResponse + return NamespacesResourceWithRawResponse(self._client.namespaces) + + @cached_property + def authentication(self) -> "AuthenticationResourceWithRawResponse": + with _RESOURCE_IMPORT_LOCK: + from .resources.authentication import AuthenticationResourceWithRawResponse + return AuthenticationResourceWithRawResponse(self._client.authentication) + + +class AsyncScalarApiWithRawResponse: + def __init__(self, client: AsyncScalarApi) -> None: + self._client = client + + @cached_property + def registry(self) -> "AsyncRegistryResourceWithRawResponse": + with _RESOURCE_IMPORT_LOCK: + from .resources.registry import AsyncRegistryResourceWithRawResponse + return AsyncRegistryResourceWithRawResponse(self._client.registry) + + @cached_property + def schemas(self) -> "AsyncSchemasResourceWithRawResponse": + with _RESOURCE_IMPORT_LOCK: + from .resources.schemas import AsyncSchemasResourceWithRawResponse + return AsyncSchemasResourceWithRawResponse(self._client.schemas) + + @cached_property + def login_portals(self) -> "AsyncLoginPortalsResourceWithRawResponse": + with _RESOURCE_IMPORT_LOCK: + from .resources.login_portals import AsyncLoginPortalsResourceWithRawResponse + return AsyncLoginPortalsResourceWithRawResponse(self._client.login_portals) + + @cached_property + def rules(self) -> "AsyncRulesResourceWithRawResponse": + with _RESOURCE_IMPORT_LOCK: + from .resources.rules import AsyncRulesResourceWithRawResponse + return AsyncRulesResourceWithRawResponse(self._client.rules) + + @cached_property + def themes(self) -> "AsyncThemesResourceWithRawResponse": + with _RESOURCE_IMPORT_LOCK: + from .resources.themes import AsyncThemesResourceWithRawResponse + return AsyncThemesResourceWithRawResponse(self._client.themes) + + @cached_property + def teams(self) -> "AsyncTeamsResourceWithRawResponse": + with _RESOURCE_IMPORT_LOCK: + from .resources.teams import AsyncTeamsResourceWithRawResponse + return AsyncTeamsResourceWithRawResponse(self._client.teams) + + @cached_property + def scalar_docs(self) -> "AsyncScalarDocsResourceWithRawResponse": + with _RESOURCE_IMPORT_LOCK: + from .resources.scalar_docs import AsyncScalarDocsResourceWithRawResponse + return AsyncScalarDocsResourceWithRawResponse(self._client.scalar_docs) + + @cached_property + def namespaces(self) -> "AsyncNamespacesResourceWithRawResponse": + with _RESOURCE_IMPORT_LOCK: + from .resources.namespaces import AsyncNamespacesResourceWithRawResponse + return AsyncNamespacesResourceWithRawResponse(self._client.namespaces) + + @cached_property + def authentication(self) -> "AsyncAuthenticationResourceWithRawResponse": + with _RESOURCE_IMPORT_LOCK: + from .resources.authentication import AsyncAuthenticationResourceWithRawResponse + return AsyncAuthenticationResourceWithRawResponse(self._client.authentication) + + +class ScalarApiWithStreamingResponse: + def __init__(self, client: ScalarApi) -> None: + self._client = client + + @cached_property + def registry(self) -> "RegistryResourceWithStreamingResponse": + with _RESOURCE_IMPORT_LOCK: + from .resources.registry import RegistryResourceWithStreamingResponse + return RegistryResourceWithStreamingResponse(self._client.registry) + + @cached_property + def schemas(self) -> "SchemasResourceWithStreamingResponse": + with _RESOURCE_IMPORT_LOCK: + from .resources.schemas import SchemasResourceWithStreamingResponse + return SchemasResourceWithStreamingResponse(self._client.schemas) + + @cached_property + def login_portals(self) -> "LoginPortalsResourceWithStreamingResponse": + with _RESOURCE_IMPORT_LOCK: + from .resources.login_portals import LoginPortalsResourceWithStreamingResponse + return LoginPortalsResourceWithStreamingResponse(self._client.login_portals) + + @cached_property + def rules(self) -> "RulesResourceWithStreamingResponse": + with _RESOURCE_IMPORT_LOCK: + from .resources.rules import RulesResourceWithStreamingResponse + return RulesResourceWithStreamingResponse(self._client.rules) + + @cached_property + def themes(self) -> "ThemesResourceWithStreamingResponse": + with _RESOURCE_IMPORT_LOCK: + from .resources.themes import ThemesResourceWithStreamingResponse + return ThemesResourceWithStreamingResponse(self._client.themes) + + @cached_property + def teams(self) -> "TeamsResourceWithStreamingResponse": + with _RESOURCE_IMPORT_LOCK: + from .resources.teams import TeamsResourceWithStreamingResponse + return TeamsResourceWithStreamingResponse(self._client.teams) + + @cached_property + def scalar_docs(self) -> "ScalarDocsResourceWithStreamingResponse": + with _RESOURCE_IMPORT_LOCK: + from .resources.scalar_docs import ScalarDocsResourceWithStreamingResponse + return ScalarDocsResourceWithStreamingResponse(self._client.scalar_docs) + + @cached_property + def namespaces(self) -> "NamespacesResourceWithStreamingResponse": + with _RESOURCE_IMPORT_LOCK: + from .resources.namespaces import NamespacesResourceWithStreamingResponse + return NamespacesResourceWithStreamingResponse(self._client.namespaces) + + @cached_property + def authentication(self) -> "AuthenticationResourceWithStreamingResponse": + with _RESOURCE_IMPORT_LOCK: + from .resources.authentication import AuthenticationResourceWithStreamingResponse + return AuthenticationResourceWithStreamingResponse(self._client.authentication) + + +class AsyncScalarApiWithStreamingResponse: + def __init__(self, client: AsyncScalarApi) -> None: + self._client = client + + @cached_property + def registry(self) -> "AsyncRegistryResourceWithStreamingResponse": + with _RESOURCE_IMPORT_LOCK: + from .resources.registry import AsyncRegistryResourceWithStreamingResponse + return AsyncRegistryResourceWithStreamingResponse(self._client.registry) + + @cached_property + def schemas(self) -> "AsyncSchemasResourceWithStreamingResponse": + with _RESOURCE_IMPORT_LOCK: + from .resources.schemas import AsyncSchemasResourceWithStreamingResponse + return AsyncSchemasResourceWithStreamingResponse(self._client.schemas) + + @cached_property + def login_portals(self) -> "AsyncLoginPortalsResourceWithStreamingResponse": + with _RESOURCE_IMPORT_LOCK: + from .resources.login_portals import AsyncLoginPortalsResourceWithStreamingResponse + return AsyncLoginPortalsResourceWithStreamingResponse(self._client.login_portals) + + @cached_property + def rules(self) -> "AsyncRulesResourceWithStreamingResponse": + with _RESOURCE_IMPORT_LOCK: + from .resources.rules import AsyncRulesResourceWithStreamingResponse + return AsyncRulesResourceWithStreamingResponse(self._client.rules) + + @cached_property + def themes(self) -> "AsyncThemesResourceWithStreamingResponse": + with _RESOURCE_IMPORT_LOCK: + from .resources.themes import AsyncThemesResourceWithStreamingResponse + return AsyncThemesResourceWithStreamingResponse(self._client.themes) + + @cached_property + def teams(self) -> "AsyncTeamsResourceWithStreamingResponse": + with _RESOURCE_IMPORT_LOCK: + from .resources.teams import AsyncTeamsResourceWithStreamingResponse + return AsyncTeamsResourceWithStreamingResponse(self._client.teams) + + @cached_property + def scalar_docs(self) -> "AsyncScalarDocsResourceWithStreamingResponse": + with _RESOURCE_IMPORT_LOCK: + from .resources.scalar_docs import AsyncScalarDocsResourceWithStreamingResponse + return AsyncScalarDocsResourceWithStreamingResponse(self._client.scalar_docs) + + @cached_property + def namespaces(self) -> "AsyncNamespacesResourceWithStreamingResponse": + with _RESOURCE_IMPORT_LOCK: + from .resources.namespaces import AsyncNamespacesResourceWithStreamingResponse + return AsyncNamespacesResourceWithStreamingResponse(self._client.namespaces) + + @cached_property + def authentication(self) -> "AsyncAuthenticationResourceWithStreamingResponse": + with _RESOURCE_IMPORT_LOCK: + from .resources.authentication import AsyncAuthenticationResourceWithStreamingResponse + return AsyncAuthenticationResourceWithStreamingResponse(self._client.authentication) + + +# Alias names for the documented `Client` / `AsyncClient` symbols. +Client = ScalarApi +AsyncClient = AsyncScalarApi diff --git a/src/_compat.py b/src/_compat.py new file mode 100644 index 0000000..e6690a4 --- /dev/null +++ b/src/_compat.py @@ -0,0 +1,226 @@ +from __future__ import annotations + +from typing import TYPE_CHECKING, Any, Union, Generic, TypeVar, Callable, cast, overload +from datetime import date, datetime +from typing_extensions import Self, Literal, TypedDict + +import pydantic +from pydantic.fields import FieldInfo + +from ._types import IncEx, StrBytesIntFloat + +_T = TypeVar("_T") +_ModelT = TypeVar("_ModelT", bound=pydantic.BaseModel) + +# --------------- Pydantic v2, v3 compatibility --------------- + +# Pyright incorrectly reports some of our functions as overriding a method when they don't +# pyright: reportIncompatibleMethodOverride=false + +PYDANTIC_V1 = pydantic.VERSION.startswith("1.") + +if TYPE_CHECKING: + + def parse_date(value: date | StrBytesIntFloat) -> date: # noqa: ARG001 + ... + + def parse_datetime(value: Union[datetime, StrBytesIntFloat]) -> datetime: # noqa: ARG001 + ... + + def get_args(t: type[Any]) -> tuple[Any, ...]: # noqa: ARG001 + ... + + def is_union(tp: type[Any] | None) -> bool: # noqa: ARG001 + ... + + def get_origin(t: type[Any]) -> type[Any] | None: # noqa: ARG001 + ... + + def is_literal_type(type_: type[Any]) -> bool: # noqa: ARG001 + ... + + def is_typeddict(type_: type[Any]) -> bool: # noqa: ARG001 + ... + +else: + # v1 re-exports + if PYDANTIC_V1: + from pydantic.typing import ( + get_args as get_args, + is_union as is_union, + get_origin as get_origin, + is_typeddict as is_typeddict, + is_literal_type as is_literal_type, + ) + from pydantic.datetime_parse import parse_date as parse_date, parse_datetime as parse_datetime + else: + from ._utils import ( + get_args as get_args, + is_union as is_union, + get_origin as get_origin, + parse_date as parse_date, + is_typeddict as is_typeddict, + parse_datetime as parse_datetime, + is_literal_type as is_literal_type, + ) + + +# refactored config +if TYPE_CHECKING: + from pydantic import ConfigDict as ConfigDict +else: + if PYDANTIC_V1: + # TODO: provide an error message here? + ConfigDict = None + else: + from pydantic import ConfigDict as ConfigDict + + +# renamed methods / properties +def parse_obj(model: type[_ModelT], value: object) -> _ModelT: + if PYDANTIC_V1: + return cast(_ModelT, model.parse_obj(value)) # pyright: ignore[reportDeprecated, reportUnnecessaryCast] + else: + return model.model_validate(value) + + +def field_is_required(field: FieldInfo) -> bool: + if PYDANTIC_V1: + return field.required # type: ignore + return field.is_required() + + +def field_get_default(field: FieldInfo) -> Any: + value = field.get_default() + if PYDANTIC_V1: + return value + from pydantic_core import PydanticUndefined + + if value == PydanticUndefined: + return None + return value + + +def field_outer_type(field: FieldInfo) -> Any: + if PYDANTIC_V1: + return field.outer_type_ # type: ignore + return field.annotation + + +def get_model_config(model: type[pydantic.BaseModel]) -> Any: + if PYDANTIC_V1: + return model.__config__ # type: ignore + return model.model_config + + +def get_model_fields(model: type[pydantic.BaseModel]) -> dict[str, FieldInfo]: + if PYDANTIC_V1: + return model.__fields__ # type: ignore + return model.model_fields + + +def model_copy(model: _ModelT, *, deep: bool = False) -> _ModelT: + if PYDANTIC_V1: + return model.copy(deep=deep) # type: ignore + return model.model_copy(deep=deep) + + +def model_json(model: pydantic.BaseModel, *, indent: int | None = None) -> str: + if PYDANTIC_V1: + return model.json(indent=indent) # type: ignore + return model.model_dump_json(indent=indent) + + +class _ModelDumpKwargs(TypedDict, total=False): + by_alias: bool + + +def model_dump( + model: pydantic.BaseModel, + *, + exclude: IncEx | None = None, + exclude_unset: bool = False, + exclude_defaults: bool = False, + warnings: bool = True, + mode: Literal["json", "python"] = "python", + by_alias: bool | None = None, +) -> dict[str, Any]: + if (not PYDANTIC_V1) or hasattr(model, "model_dump"): + kwargs: _ModelDumpKwargs = {} + if by_alias is not None: + kwargs["by_alias"] = by_alias + return model.model_dump( + mode=mode, + exclude=exclude, + exclude_unset=exclude_unset, + exclude_defaults=exclude_defaults, + # warnings are not supported in Pydantic v1 + warnings=True if PYDANTIC_V1 else warnings, + **kwargs, + ) + return cast( + "dict[str, Any]", + model.dict( # pyright: ignore[reportDeprecated, reportUnnecessaryCast] + exclude=exclude, exclude_unset=exclude_unset, exclude_defaults=exclude_defaults, by_alias=bool(by_alias) + ), + ) + + +def model_parse(model: type[_ModelT], data: Any) -> _ModelT: + if PYDANTIC_V1: + return model.parse_obj(data) # pyright: ignore[reportDeprecated] + return model.model_validate(data) + + +# generic models +if TYPE_CHECKING: + + class GenericModel(pydantic.BaseModel): ... + +else: + if PYDANTIC_V1: + import pydantic.generics + + class GenericModel(pydantic.generics.GenericModel, pydantic.BaseModel): ... + else: + # there no longer needs to be a distinction in v2 but + # we still have to create our own subclass to avoid + # inconsistent MRO ordering errors + class GenericModel(pydantic.BaseModel): ... + + +# cached properties +if TYPE_CHECKING: + cached_property = property + + # we define a separate type (copied from typeshed) + # that represents that `cached_property` is `set`able + # at runtime, which differs from `@property`. + # + # this is a separate type as editors likely special case + # `@property` and we don't want to cause issues just to have + # more helpful internal types. + + class typed_cached_property(Generic[_T]): + func: Callable[[Any], _T] + attrname: str | None + + def __init__(self, func: Callable[[Any], _T]) -> None: ... + + @overload + def __get__(self, instance: None, owner: type[Any] | None = None) -> Self: ... + + @overload + def __get__(self, instance: object, owner: type[Any] | None = None) -> _T: ... + + def __get__(self, instance: object, owner: type[Any] | None = None) -> _T | Self: + raise NotImplementedError() + + def __set_name__(self, owner: type[Any], name: str) -> None: ... + + # __set__ is not defined at runtime, but @cached_property is designed to be settable + def __set__(self, instance: object, value: _T) -> None: ... +else: + from functools import cached_property as cached_property + + typed_cached_property = cached_property diff --git a/src/_constants.py b/src/_constants.py new file mode 100644 index 0000000..969d075 --- /dev/null +++ b/src/_constants.py @@ -0,0 +1,14 @@ +# File generated from our OpenAPI spec by Scalar. See CONTRIBUTING.md for details. + +import httpx + +RAW_RESPONSE_HEADER = "X-Scalar-Raw-Response" +OVERRIDE_CAST_TO_HEADER = "____scalar_override_cast_to" + +# default timeout is 1 minute +DEFAULT_TIMEOUT = httpx.Timeout(timeout=60, connect=5.0) +DEFAULT_MAX_RETRIES = 2 +DEFAULT_CONNECTION_LIMITS = httpx.Limits(max_connections=100, max_keepalive_connections=20) + +INITIAL_RETRY_DELAY = 0.5 +MAX_RETRY_DELAY = 8.0 diff --git a/src/_event_handler.py b/src/_event_handler.py new file mode 100644 index 0000000..d84a24d --- /dev/null +++ b/src/_event_handler.py @@ -0,0 +1,85 @@ +# File generated from our OpenAPI spec by Scalar. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import threading +from typing import Any, Callable + +EventHandler = Callable[..., Any] + + +class EventHandlerRegistry: + """Thread-safe (optional) registry of event handlers.""" + + def __init__(self, *, use_lock: bool = False) -> None: + self._handlers: dict[str, list[EventHandler]] = {} + self._once_ids: set[int] = set() + self._lock: threading.Lock | None = threading.Lock() if use_lock else None + + def _acquire(self) -> None: + if self._lock is not None: + self._lock.acquire() + + def _release(self) -> None: + if self._lock is not None: + self._lock.release() + + def add(self, event_type: str, handler: EventHandler, *, once: bool = False) -> None: + self._acquire() + try: + handlers = self._handlers.setdefault(event_type, []) + handlers.append(handler) + if once: + self._once_ids.add(id(handler)) + finally: + self._release() + + def remove(self, event_type: str, handler: EventHandler) -> None: + self._acquire() + try: + handlers = self._handlers.get(event_type) + if handlers is not None: + try: + handlers.remove(handler) + except ValueError: + pass + self._once_ids.discard(id(handler)) + finally: + self._release() + + def get_handlers(self, event_type: str) -> list[EventHandler]: + """Return a snapshot of handlers for the given event type, removing once-handlers.""" + self._acquire() + try: + handlers = self._handlers.get(event_type) + if not handlers: + return [] + result = list(handlers) + to_remove = [h for h in result if id(h) in self._once_ids] + for h in to_remove: + handlers.remove(h) + self._once_ids.discard(id(h)) + return result + finally: + self._release() + + def has_handlers(self, event_type: str) -> bool: + self._acquire() + try: + handlers = self._handlers.get(event_type) + return bool(handlers) + finally: + self._release() + + def merge_into(self, target: EventHandlerRegistry) -> None: + """Move all handlers from this registry into *target*, then clear self.""" + self._acquire() + try: + for event_type, handlers in self._handlers.items(): + for handler in handlers: + once = id(handler) in self._once_ids + target.add(event_type, handler, once=once) + self._handlers.clear() + self._once_ids.clear() + finally: + self._release() diff --git a/src/_exceptions.py b/src/_exceptions.py new file mode 100644 index 0000000..e448b86 --- /dev/null +++ b/src/_exceptions.py @@ -0,0 +1,126 @@ +# File generated from our OpenAPI spec by Scalar. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal + +import httpx + +__all__ = [ + "BadRequestError", + "AuthenticationError", + "PermissionDeniedError", + "NotFoundError", + "ConflictError", + "UnprocessableEntityError", + "RateLimitError", + "InternalServerError", + "WebSocketConnectionClosedError", + "WebSocketQueueFullError", +] + + +class ScalarApiError(Exception): + pass + + +class APIError(ScalarApiError): + message: str + request: httpx.Request + + body: object | None + """The API response body. + + If the API responded with a valid JSON structure then this property will be the + decoded result. + + If it isn't a valid JSON structure then this will be the raw response. + + If there was no response associated with this error then it will be `None`. + """ + + def __init__(self, message: str, request: httpx.Request, *, body: object | None) -> None: # noqa: ARG002 + super().__init__(message) + self.request = request + self.message = message + self.body = body + + +class APIResponseValidationError(APIError): + response: httpx.Response + status_code: int + + def __init__(self, response: httpx.Response, body: object | None, *, message: str | None = None) -> None: + super().__init__(message or "Data returned by API invalid for expected schema.", response.request, body=body) + self.response = response + self.status_code = response.status_code + + +class APIStatusError(APIError): + """Raised when an API response has a status code of 4xx or 5xx.""" + + response: httpx.Response + status_code: int + + def __init__(self, message: str, *, response: httpx.Response, body: object | None) -> None: + super().__init__(message, response.request, body=body) + self.response = response + self.status_code = response.status_code + + +class APIConnectionError(APIError): + def __init__(self, *, message: str = "Connection error.", request: httpx.Request) -> None: + super().__init__(message, request, body=None) + + +class APITimeoutError(APIConnectionError): + def __init__(self, request: httpx.Request) -> None: + super().__init__(message="Request timed out.", request=request) + + +class BadRequestError(APIStatusError): + status_code: Literal[400] = 400 # pyright: ignore[reportIncompatibleVariableOverride] + + +class AuthenticationError(APIStatusError): + status_code: Literal[401] = 401 # pyright: ignore[reportIncompatibleVariableOverride] + + +class PermissionDeniedError(APIStatusError): + status_code: Literal[403] = 403 # pyright: ignore[reportIncompatibleVariableOverride] + + +class NotFoundError(APIStatusError): + status_code: Literal[404] = 404 # pyright: ignore[reportIncompatibleVariableOverride] + + +class ConflictError(APIStatusError): + status_code: Literal[409] = 409 # pyright: ignore[reportIncompatibleVariableOverride] + + +class UnprocessableEntityError(APIStatusError): + status_code: Literal[422] = 422 # pyright: ignore[reportIncompatibleVariableOverride] + + +class RateLimitError(APIStatusError): + status_code: Literal[429] = 429 # pyright: ignore[reportIncompatibleVariableOverride] + + +class InternalServerError(APIStatusError): + pass + + +class WebSocketConnectionClosedError(ScalarApiError): + """Raised when a WebSocket connection closes with unsent messages.""" + + unsent_messages: list[str] + + def __init__(self, message: str, *, unsent_messages: list[str]) -> None: + super().__init__(message) + self.unsent_messages = unsent_messages + + +class WebSocketQueueFullError(ScalarApiError): + """Raised when the outgoing WebSocket message queue exceeds its byte-size limit.""" + + pass diff --git a/src/_files.py b/src/_files.py new file mode 100644 index 0000000..76da9e0 --- /dev/null +++ b/src/_files.py @@ -0,0 +1,173 @@ +from __future__ import annotations + +import io +import os +import pathlib +from typing import Sequence, cast, overload +from typing_extensions import TypeVar, TypeGuard + +import anyio + +from ._types import ( + FileTypes, + FileContent, + RequestFiles, + HttpxFileTypes, + Base64FileInput, + HttpxFileContent, + HttpxRequestFiles, +) +from ._utils import is_list, is_mapping, is_tuple_t, is_mapping_t, is_sequence_t + +_T = TypeVar("_T") + + +def is_base64_file_input(obj: object) -> TypeGuard[Base64FileInput]: + return isinstance(obj, io.IOBase) or isinstance(obj, os.PathLike) + + +def is_file_content(obj: object) -> TypeGuard[FileContent]: + return ( + isinstance(obj, bytes) or isinstance(obj, tuple) or isinstance(obj, io.IOBase) or isinstance(obj, os.PathLike) + ) + + +def assert_is_file_content(obj: object, *, key: str | None = None) -> None: + if not is_file_content(obj): + prefix = f"Expected entry at `{key}`" if key is not None else f"Expected file input `{obj!r}`" + raise RuntimeError( + f"{prefix} to be bytes, an io.IOBase instance, PathLike or a tuple but received {type(obj)} instead." + ) from None + + +@overload +def to_httpx_files(files: None) -> None: ... + + +@overload +def to_httpx_files(files: RequestFiles) -> HttpxRequestFiles: ... + + +def to_httpx_files(files: RequestFiles | None) -> HttpxRequestFiles | None: + if files is None: + return None + + if is_mapping_t(files): + files = {key: _transform_file(file) for key, file in files.items()} + elif is_sequence_t(files): + files = [(key, _transform_file(file)) for key, file in files] + else: + raise TypeError(f"Unexpected file type input {type(files)}, expected mapping or sequence") + + return files + + +def _transform_file(file: FileTypes) -> HttpxFileTypes: + if is_file_content(file): + if isinstance(file, os.PathLike): + path = pathlib.Path(file) + return (path.name, path.read_bytes()) + + return file + + if is_tuple_t(file): + return (file[0], read_file_content(file[1]), *file[2:]) + + raise TypeError(f"Expected file types input to be a FileContent type or to be a tuple") + + +def read_file_content(file: FileContent) -> HttpxFileContent: + if isinstance(file, os.PathLike): + return pathlib.Path(file).read_bytes() + return file + + +@overload +async def async_to_httpx_files(files: None) -> None: ... + + +@overload +async def async_to_httpx_files(files: RequestFiles) -> HttpxRequestFiles: ... + + +async def async_to_httpx_files(files: RequestFiles | None) -> HttpxRequestFiles | None: + if files is None: + return None + + if is_mapping_t(files): + files = {key: await _async_transform_file(file) for key, file in files.items()} + elif is_sequence_t(files): + files = [(key, await _async_transform_file(file)) for key, file in files] + else: + raise TypeError(f"Unexpected file type input {type(files)}, expected mapping or sequence") + + return files + + +async def _async_transform_file(file: FileTypes) -> HttpxFileTypes: + if is_file_content(file): + if isinstance(file, os.PathLike): + path = anyio.Path(file) + return (path.name, await path.read_bytes()) + + return file + + if is_tuple_t(file): + return (file[0], await async_read_file_content(file[1]), *file[2:]) + + raise TypeError(f"Expected file types input to be a FileContent type or to be a tuple") + + +async def async_read_file_content(file: FileContent) -> HttpxFileContent: + if isinstance(file, os.PathLike): + return await anyio.Path(file).read_bytes() + + return file + + +def deepcopy_with_paths(item: _T, paths: Sequence[Sequence[str]]) -> _T: + """Copy only the containers along the given paths. + + Used to guard against mutation by extract_files without copying the entire structure. + Only dicts and lists that lie on a path are copied; everything else + is returned by reference. + + For example, given paths=[["foo", "files", "file"]] and the structure: + { + "foo": { + "bar": {"baz": {}}, + "files": {"file": } + } + } + The root dict, "foo", and "files" are copied (they lie on the path). + "bar" and "baz" are returned by reference (off the path). + """ + return _deepcopy_with_paths(item, paths, 0) + + +def _deepcopy_with_paths(item: _T, paths: Sequence[Sequence[str]], index: int) -> _T: + if not paths: + return item + if is_mapping(item): + key_to_paths: dict[str, list[Sequence[str]]] = {} + for path in paths: + if index < len(path): + key_to_paths.setdefault(path[index], []).append(path) + + # if no path continues through this mapping, it won't be mutated and copying it is redundant + if not key_to_paths: + return item + + result = dict(item) + for key, subpaths in key_to_paths.items(): + if key in result: + result[key] = _deepcopy_with_paths(result[key], subpaths, index + 1) + return cast(_T, result) + if is_list(item): + array_paths = [path for path in paths if index < len(path) and path[index] == ""] + + # if no path expects a list here, nothing will be mutated inside it - return by reference + if not array_paths: + return cast(_T, item) + return cast(_T, [_deepcopy_with_paths(entry, array_paths, index + 1) for entry in item]) + return item diff --git a/src/_models.py b/src/_models.py new file mode 100644 index 0000000..ce728eb --- /dev/null +++ b/src/_models.py @@ -0,0 +1,962 @@ +from __future__ import annotations + +import os +import inspect +import weakref +from typing import ( + IO, + TYPE_CHECKING, + Any, + Type, + Union, + Generic, + TypeVar, + Callable, + Iterable, + Optional, + AsyncIterable, + cast, +) +from datetime import date, datetime +from typing_extensions import ( + List, + Unpack, + Literal, + ClassVar, + Protocol, + Required, + Annotated, + ParamSpec, + TypeAlias, + TypedDict, + TypeGuard, + final, + override, + runtime_checkable, +) + +import pydantic +from pydantic.fields import FieldInfo + +from ._types import ( + Body, + IncEx, + Query, + ModelT, + Headers, + Timeout, + NotGiven, + AnyMapping, + HttpxRequestFiles, +) +from ._utils import ( + PropertyInfo, + is_list, + is_given, + json_safe, + lru_cache, + is_mapping, + parse_date, + coerce_boolean, + parse_datetime, + strip_not_given, + extract_type_arg, + is_annotated_type, + is_type_alias_type, + strip_annotated_type, +) +from ._compat import ( + PYDANTIC_V1, + ConfigDict, + GenericModel as BaseGenericModel, + get_args, + is_union, + parse_obj, + get_origin, + is_literal_type, + get_model_config, + get_model_fields, + field_get_default, +) +from ._constants import RAW_RESPONSE_HEADER + +if TYPE_CHECKING: + from pydantic import GetCoreSchemaHandler, ValidatorFunctionWrapHandler + from pydantic_core import CoreSchema, core_schema + from pydantic_core.core_schema import ModelField, ModelSchema, LiteralSchema, ModelFieldsSchema +else: + try: + from pydantic_core import CoreSchema, core_schema + except ImportError: + CoreSchema = None + core_schema = None + +__all__ = ["BaseModel", "GenericModel"] + +_T = TypeVar("_T") +_BaseModelT = TypeVar("_BaseModelT", bound="BaseModel") + +P = ParamSpec("P") + + +@runtime_checkable +class _ConfigProtocol(Protocol): + allow_population_by_field_name: bool + + +class BaseModel(pydantic.BaseModel): + if PYDANTIC_V1: + + @property + @override + def model_fields_set(self) -> set[str]: + # a forwards-compat shim for pydantic v2 + return self.__fields_set__ # type: ignore + + class Config(pydantic.BaseConfig): # pyright: ignore[reportDeprecated] + extra: Any = pydantic.Extra.allow # type: ignore + else: + model_config: ClassVar[ConfigDict] = ConfigDict( + extra="allow", defer_build=coerce_boolean(os.environ.get("DEFER_PYDANTIC_BUILD", "true")) + ) + + def to_dict( + self, + *, + mode: Literal["json", "python"] = "python", + use_api_names: bool = True, + exclude_unset: bool = True, + exclude_defaults: bool = False, + exclude_none: bool = False, + warnings: bool = True, + ) -> dict[str, object]: + """Recursively generate a dictionary representation of the model, optionally specifying which fields to include or exclude. + + By default, fields that were not set by the API will not be included, + and keys will match the API response, *not* the property names from the model. + + For example, if the API responds with `"fooBar": true` but we've defined a `foo_bar: bool` property, + the output will use the `"fooBar"` key (unless `use_api_names=False` is passed). + + Args: + mode: + If mode is 'json', the dictionary will only contain JSON serializable types. e.g. `datetime` will be turned into a string, `"2024-3-22T18:11:19.117000Z"`. + If mode is 'python', the dictionary may contain any Python objects. e.g. `datetime(2024, 3, 22)` + + use_api_names: Whether to use the key that the API responded with or the property name. Defaults to `True`. + exclude_unset: Whether to exclude fields that have not been explicitly set. + exclude_defaults: Whether to exclude fields that are set to their default value from the output. + exclude_none: Whether to exclude fields that have a value of `None` from the output. + warnings: Whether to log warnings when invalid fields are encountered. This is only supported in Pydantic v2. + """ + return self.model_dump( + mode=mode, + by_alias=use_api_names, + exclude_unset=exclude_unset, + exclude_defaults=exclude_defaults, + exclude_none=exclude_none, + warnings=warnings, + ) + + def to_json( + self, + *, + indent: int | None = 2, + use_api_names: bool = True, + exclude_unset: bool = True, + exclude_defaults: bool = False, + exclude_none: bool = False, + warnings: bool = True, + ) -> str: + """Generates a JSON string representing this model as it would be received from or sent to the API (but with indentation). + + By default, fields that were not set by the API will not be included, + and keys will match the API response, *not* the property names from the model. + + For example, if the API responds with `"fooBar": true` but we've defined a `foo_bar: bool` property, + the output will use the `"fooBar"` key (unless `use_api_names=False` is passed). + + Args: + indent: Indentation to use in the JSON output. If `None` is passed, the output will be compact. Defaults to `2` + use_api_names: Whether to use the key that the API responded with or the property name. Defaults to `True`. + exclude_unset: Whether to exclude fields that have not been explicitly set. + exclude_defaults: Whether to exclude fields that have the default value. + exclude_none: Whether to exclude fields that have a value of `None`. + warnings: Whether to show any warnings that occurred during serialization. This is only supported in Pydantic v2. + """ + return self.model_dump_json( + indent=indent, + by_alias=use_api_names, + exclude_unset=exclude_unset, + exclude_defaults=exclude_defaults, + exclude_none=exclude_none, + warnings=warnings, + ) + + @override + def __str__(self) -> str: + # mypy complains about an invalid self arg + return f"{self.__repr_name__()}({self.__repr_str__(', ')})" # type: ignore[misc] + + # Override the 'construct' method in a way that supports recursive parsing without validation. + # Based on https://github.com/samuelcolvin/pydantic/issues/1168#issuecomment-817742836. + @classmethod + @override + def construct( # pyright: ignore[reportIncompatibleMethodOverride] + __cls: Type[ModelT], + _fields_set: set[str] | None = None, + **values: object, + ) -> ModelT: + m = __cls.__new__(__cls) + fields_values: dict[str, object] = {} + + config = get_model_config(__cls) + populate_by_name = ( + config.allow_population_by_field_name + if isinstance(config, _ConfigProtocol) + else config.get("populate_by_name") + ) + + if _fields_set is None: + _fields_set = set() + + model_fields = get_model_fields(__cls) + for name, field in model_fields.items(): + key = field.alias + if key is None or (key not in values and populate_by_name): + key = name + + if key in values: + fields_values[name] = _construct_field(value=values[key], field=field, key=key) + _fields_set.add(name) + else: + fields_values[name] = field_get_default(field) + + extra_field_type = _get_extra_fields_type(__cls) + + _extra = {} + for key, value in values.items(): + if key not in model_fields: + parsed = construct_type(value=value, type_=extra_field_type) if extra_field_type is not None else value + + if PYDANTIC_V1: + _fields_set.add(key) + fields_values[key] = parsed + else: + _extra[key] = parsed + + object.__setattr__(m, "__dict__", fields_values) + + if PYDANTIC_V1: + # init_private_attributes() does not exist in v2 + m._init_private_attributes() # type: ignore + + # copied from Pydantic v1's `construct()` method + object.__setattr__(m, "__fields_set__", _fields_set) + else: + # these properties are copied from Pydantic's `model_construct()` method + object.__setattr__(m, "__pydantic_private__", None) + object.__setattr__(m, "__pydantic_extra__", _extra) + object.__setattr__(m, "__pydantic_fields_set__", _fields_set) + + return m + + if not TYPE_CHECKING: + # type checkers incorrectly complain about this assignment + # because the type signatures are technically different + # although not in practice + model_construct = construct + + if PYDANTIC_V1: + # we define aliases for some of the new pydantic v2 methods so + # that we can just document these methods without having to specify + # a specific pydantic version as some users may not know which + # pydantic version they are currently using + + @override + def model_dump( + self, + *, + mode: Literal["json", "python"] | str = "python", + include: IncEx | None = None, + exclude: IncEx | None = None, + context: Any | None = None, + by_alias: bool | None = None, + exclude_unset: bool = False, + exclude_defaults: bool = False, + exclude_none: bool = False, + exclude_computed_fields: bool = False, + round_trip: bool = False, + warnings: bool | Literal["none", "warn", "error"] = True, + fallback: Callable[[Any], Any] | None = None, + serialize_as_any: bool = False, + ) -> dict[str, Any]: + """Usage docs: https://docs.pydantic.dev/2.4/concepts/serialization/#modelmodel_dump + + Generate a dictionary representation of the model, optionally specifying which fields to include or exclude. + + Args: + mode: The mode in which `to_python` should run. + If mode is 'json', the output will only contain JSON serializable types. + If mode is 'python', the output may contain non-JSON-serializable Python objects. + include: A set of fields to include in the output. + exclude: A set of fields to exclude from the output. + context: Additional context to pass to the serializer. + by_alias: Whether to use the field's alias in the dictionary key if defined. + exclude_unset: Whether to exclude fields that have not been explicitly set. + exclude_defaults: Whether to exclude fields that are set to their default value. + exclude_none: Whether to exclude fields that have a value of `None`. + exclude_computed_fields: Whether to exclude computed fields. + While this can be useful for round-tripping, it is usually recommended to use the dedicated + `round_trip` parameter instead. + round_trip: If True, dumped values should be valid as input for non-idempotent types such as Json[T]. + warnings: How to handle serialization errors. False/"none" ignores them, True/"warn" logs errors, + "error" raises a [`PydanticSerializationError`][pydantic_core.PydanticSerializationError]. + fallback: A function to call when an unknown value is encountered. If not provided, + a [`PydanticSerializationError`][pydantic_core.PydanticSerializationError] error is raised. + serialize_as_any: Whether to serialize fields with duck-typing serialization behavior. + + Returns: + A dictionary representation of the model. + """ + if mode not in {"json", "python"}: + raise ValueError("mode must be either 'json' or 'python'") + if round_trip != False: + raise ValueError("round_trip is only supported in Pydantic v2") + if warnings != True: + raise ValueError("warnings is only supported in Pydantic v2") + if context is not None: + raise ValueError("context is only supported in Pydantic v2") + if serialize_as_any != False: + raise ValueError("serialize_as_any is only supported in Pydantic v2") + if fallback is not None: + raise ValueError("fallback is only supported in Pydantic v2") + if exclude_computed_fields != False: + raise ValueError("exclude_computed_fields is only supported in Pydantic v2") + dumped = super().dict( # pyright: ignore[reportDeprecated] + include=include, + exclude=exclude, + by_alias=by_alias if by_alias is not None else False, + exclude_unset=exclude_unset, + exclude_defaults=exclude_defaults, + exclude_none=exclude_none, + ) + + return cast("dict[str, Any]", json_safe(dumped)) if mode == "json" else dumped + + @override + def model_dump_json( + self, + *, + indent: int | None = None, + ensure_ascii: bool = False, + include: IncEx | None = None, + exclude: IncEx | None = None, + context: Any | None = None, + by_alias: bool | None = None, + exclude_unset: bool = False, + exclude_defaults: bool = False, + exclude_none: bool = False, + exclude_computed_fields: bool = False, + round_trip: bool = False, + warnings: bool | Literal["none", "warn", "error"] = True, + fallback: Callable[[Any], Any] | None = None, + serialize_as_any: bool = False, + ) -> str: + """Usage docs: https://docs.pydantic.dev/2.4/concepts/serialization/#modelmodel_dump_json + + Generates a JSON representation of the model using Pydantic's `to_json` method. + + Args: + indent: Indentation to use in the JSON output. If None is passed, the output will be compact. + include: Field(s) to include in the JSON output. Can take either a string or set of strings. + exclude: Field(s) to exclude from the JSON output. Can take either a string or set of strings. + by_alias: Whether to serialize using field aliases. + exclude_unset: Whether to exclude fields that have not been explicitly set. + exclude_defaults: Whether to exclude fields that have the default value. + exclude_none: Whether to exclude fields that have a value of `None`. + round_trip: Whether to use serialization/deserialization between JSON and class instance. + warnings: Whether to show any warnings that occurred during serialization. + + Returns: + A JSON string representation of the model. + """ + if round_trip != False: + raise ValueError("round_trip is only supported in Pydantic v2") + if warnings != True: + raise ValueError("warnings is only supported in Pydantic v2") + if context is not None: + raise ValueError("context is only supported in Pydantic v2") + if serialize_as_any != False: + raise ValueError("serialize_as_any is only supported in Pydantic v2") + if fallback is not None: + raise ValueError("fallback is only supported in Pydantic v2") + if ensure_ascii != False: + raise ValueError("ensure_ascii is only supported in Pydantic v2") + if exclude_computed_fields != False: + raise ValueError("exclude_computed_fields is only supported in Pydantic v2") + return super().json( # type: ignore[reportDeprecated] + indent=indent, + include=include, + exclude=exclude, + by_alias=by_alias if by_alias is not None else False, + exclude_unset=exclude_unset, + exclude_defaults=exclude_defaults, + exclude_none=exclude_none, + ) + + +class _EagerIterable(list[_T], Generic[_T]): + """ + Accepts any Iterable[T] input (including generators), consumes it + eagerly, and validates all items upfront. + + Validation preserves the original container type where possible + (e.g. a set[T] stays a set[T]). Serialization (model_dump / JSON) + always emits a list — round-tripping through model_dump() will not + restore the original container type. + """ + + @classmethod + def __get_pydantic_core_schema__( + cls, + source_type: Any, + handler: GetCoreSchemaHandler, + ) -> CoreSchema: + (item_type,) = get_args(source_type) or (Any,) + item_schema: CoreSchema = handler.generate_schema(item_type) + list_of_items_schema: CoreSchema = core_schema.list_schema(item_schema) + + return core_schema.no_info_wrap_validator_function( + cls._validate, + list_of_items_schema, + serialization=core_schema.plain_serializer_function_ser_schema( + cls._serialize, + info_arg=False, + ), + ) + + @staticmethod + def _validate(v: Iterable[_T], handler: "ValidatorFunctionWrapHandler") -> Any: + original_type: type[Any] = type(v) + + # Normalize to list so list_schema can validate each item + if isinstance(v, list): + items: list[_T] = v + else: + try: + items = list(v) + except TypeError as e: + raise TypeError("Value is not iterable") from e + + # Validate items against the inner schema + validated: list[_T] = handler(items) + + # Reconstruct original container type + if original_type is list: + return validated + # str(list) produces the list's repr, not a string built from items, + # so skip reconstruction for str and its subclasses. + if issubclass(original_type, str): + return validated + try: + return original_type(validated) + except (TypeError, ValueError): + # If the type cannot be reconstructed, just return the validated list + return validated + + @staticmethod + def _serialize(v: Iterable[_T]) -> list[_T]: + """Always serialize as a list so Pydantic's JSON encoder is happy.""" + if isinstance(v, list): + return v + return list(v) + + +EagerIterable: TypeAlias = Annotated[Iterable[_T], _EagerIterable] + + +def _construct_field(value: object, field: FieldInfo, key: str) -> object: + if value is None: + return field_get_default(field) + + if PYDANTIC_V1: + type_ = cast(type, field.outer_type_) # type: ignore + else: + type_ = field.annotation # type: ignore + + if type_ is None: + raise RuntimeError(f"Unexpected field type is None for {key}") + + return construct_type(value=value, type_=type_, metadata=getattr(field, "metadata", None)) + + +def _get_extra_fields_type(cls: type[pydantic.BaseModel]) -> type | None: + if PYDANTIC_V1: + # TODO + return None + + schema = cls.__pydantic_core_schema__ + if schema["type"] == "model": + fields = schema["schema"] + if fields["type"] == "model-fields": + extras = fields.get("extras_schema") + if extras and "cls" in extras: + # mypy can't narrow the type + return extras["cls"] # type: ignore[no-any-return] + + return None + + +def is_basemodel(type_: type) -> bool: + """Returns whether or not the given type is either a `BaseModel` or a union of `BaseModel`""" + if is_union(type_): + for variant in get_args(type_): + if is_basemodel(variant): + return True + + return False + + return is_basemodel_type(type_) + + +def is_basemodel_type(type_: type) -> TypeGuard[type[BaseModel] | type[GenericModel]]: + origin = get_origin(type_) or type_ + if not inspect.isclass(origin): + return False + return issubclass(origin, BaseModel) or issubclass(origin, GenericModel) + + +def build( + base_model_cls: Callable[P, _BaseModelT], + *args: P.args, + **kwargs: P.kwargs, +) -> _BaseModelT: + """Construct a BaseModel class without validation. + + This is useful for cases where you need to instantiate a `BaseModel` + from an API response as this provides type-safe params which isn't supported + by helpers like `construct_type()`. + + ```py + build(MyModel, my_field_a="foo", my_field_b=123) + ``` + """ + if args: + raise TypeError( + "Received positional arguments which are not supported; Keyword arguments must be used instead", + ) + + return cast(_BaseModelT, construct_type(type_=base_model_cls, value=kwargs)) + + +def construct_type_unchecked(*, value: object, type_: type[_T]) -> _T: + """Loose coercion to the expected type with construction of nested values. + + Note: the returned value from this function is not guaranteed to match the + given type. + """ + return cast(_T, construct_type(value=value, type_=type_)) + + +def construct_type(*, value: object, type_: object, metadata: Optional[List[Any]] = None) -> object: + """Loose coercion to the expected type with construction of nested values. + + If the given value does not match the expected type then it is returned as-is. + """ + + # store a reference to the original type we were given before we extract any inner + # types so that we can properly resolve forward references in `TypeAliasType` annotations + original_type = None + + # we allow `object` as the input type because otherwise, passing things like + # `Literal['value']` will be reported as a type error by type checkers + type_ = cast("type[object]", type_) + if is_type_alias_type(type_): + original_type = type_ # type: ignore[unreachable] + type_ = type_.__value__ # type: ignore[unreachable] + + # unwrap `Annotated[T, ...]` -> `T` + if metadata is not None and len(metadata) > 0: + meta: tuple[Any, ...] = tuple(metadata) + elif is_annotated_type(type_): + meta = get_args(type_)[1:] + type_ = extract_type_arg(type_, 0) + else: + meta = tuple() + + # we need to use the origin class for any types that are subscripted generics + # e.g. Dict[str, object] + origin = get_origin(type_) or type_ + args = get_args(type_) + + if is_union(origin): + try: + return validate_type(type_=cast("type[object]", original_type or type_), value=value) + except Exception: + pass + + # if the type is a discriminated union then we want to construct the right variant + # in the union, even if the data doesn't match exactly, otherwise we'd break code + # that relies on the constructed class types, e.g. + # + # class FooType: + # kind: Literal['foo'] + # value: str + # + # class BarType: + # kind: Literal['bar'] + # value: int + # + # without this block, if the data we get is something like `{'kind': 'bar', 'value': 'foo'}` then + # we'd end up constructing `FooType` when it should be `BarType`. + discriminator = _build_discriminated_union_meta(union=type_, meta_annotations=meta) + if discriminator and is_mapping(value): + variant_value = value.get(discriminator.field_alias_from or discriminator.field_name) + if variant_value and isinstance(variant_value, str): + variant_type = discriminator.mapping.get(variant_value) + if variant_type: + return construct_type(type_=variant_type, value=value) + + # if the data is not valid, use the first variant that doesn't fail while deserializing + for variant in args: + try: + return construct_type(value=value, type_=variant) + except Exception: + continue + + raise RuntimeError(f"Could not convert data into a valid instance of {type_}") + + if origin == dict: + if not is_mapping(value): + return value + + _, items_type = get_args(type_) # Dict[_, items_type] + return {key: construct_type(value=item, type_=items_type) for key, item in value.items()} + + if ( + not is_literal_type(type_) + and inspect.isclass(origin) + and (issubclass(origin, BaseModel) or issubclass(origin, GenericModel)) + ): + if is_list(value): + return [cast(Any, type_).construct(**entry) if is_mapping(entry) else entry for entry in value] + + if is_mapping(value): + if issubclass(type_, BaseModel): + return type_.construct(**value) # type: ignore[arg-type] + + return cast(Any, type_).construct(**value) + + if origin == list: + if not is_list(value): + return value + + inner_type = args[0] # List[inner_type] + return [construct_type(value=entry, type_=inner_type) for entry in value] + + if origin == float: + if isinstance(value, int): + coerced = float(value) + if coerced != value: + return value + return coerced + + return value + + if type_ == datetime: + try: + return parse_datetime(value) # type: ignore + except Exception: + return value + + if type_ == date: + try: + return parse_date(value) # type: ignore + except Exception: + return value + + return value + + +@runtime_checkable +class CachedDiscriminatorType(Protocol): + __discriminator__: DiscriminatorDetails + + +DISCRIMINATOR_CACHE: weakref.WeakKeyDictionary[type, DiscriminatorDetails] = weakref.WeakKeyDictionary() + + +class DiscriminatorDetails: + field_name: str + """The name of the discriminator field in the variant class, e.g. + + ```py + class Foo(BaseModel): + type: Literal['foo'] + ``` + + Will result in field_name='type' + """ + + field_alias_from: str | None + """The name of the discriminator field in the API response, e.g. + + ```py + class Foo(BaseModel): + type: Literal['foo'] = Field(alias='type_from_api') + ``` + + Will result in field_alias_from='type_from_api' + """ + + mapping: dict[str, type] + """Mapping of discriminator value to variant type, e.g. + + {'foo': FooVariant, 'bar': BarVariant} + """ + + def __init__( + self, + *, + mapping: dict[str, type], + discriminator_field: str, + discriminator_alias: str | None, + ) -> None: + self.mapping = mapping + self.field_name = discriminator_field + self.field_alias_from = discriminator_alias + + +def _build_discriminated_union_meta(*, union: type, meta_annotations: tuple[Any, ...]) -> DiscriminatorDetails | None: + cached = DISCRIMINATOR_CACHE.get(union) + if cached is not None: + return cached + + discriminator_field_name: str | None = None + + for annotation in meta_annotations: + if isinstance(annotation, PropertyInfo) and annotation.discriminator is not None: + discriminator_field_name = annotation.discriminator + break + + if not discriminator_field_name: + return None + + mapping: dict[str, type] = {} + discriminator_alias: str | None = None + + for variant in get_args(union): + variant = strip_annotated_type(variant) + if is_basemodel_type(variant): + if PYDANTIC_V1: + field_info = cast("dict[str, FieldInfo]", variant.__fields__).get(discriminator_field_name) # pyright: ignore[reportDeprecated, reportUnnecessaryCast] + if not field_info: + continue + + # Note: if one variant defines an alias then they all should + discriminator_alias = field_info.alias + + if (annotation := getattr(field_info, "annotation", None)) and is_literal_type(annotation): + for entry in get_args(annotation): + if isinstance(entry, str): + mapping[entry] = variant + else: + field = _extract_field_schema_pv2(variant, discriminator_field_name) + if not field: + continue + + # Note: if one variant defines an alias then they all should + discriminator_alias = field.get("serialization_alias") + + field_schema = field["schema"] + + if field_schema["type"] == "literal": + for entry in cast("LiteralSchema", field_schema)["expected"]: + if isinstance(entry, str): + mapping[entry] = variant + + if not mapping: + return None + + details = DiscriminatorDetails( + mapping=mapping, + discriminator_field=discriminator_field_name, + discriminator_alias=discriminator_alias, + ) + DISCRIMINATOR_CACHE.setdefault(union, details) + return details + + +def _extract_field_schema_pv2(model: type[BaseModel], field_name: str) -> ModelField | None: + schema = model.__pydantic_core_schema__ + if schema["type"] == "definitions": + schema = schema["schema"] + + if schema["type"] != "model": + return None + + schema = cast("ModelSchema", schema) + fields_schema = schema["schema"] + if fields_schema["type"] != "model-fields": + return None + + fields_schema = cast("ModelFieldsSchema", fields_schema) + field = fields_schema["fields"].get(field_name) + if not field: + return None + + return cast("ModelField", field) # pyright: ignore[reportUnnecessaryCast] + + +def validate_type(*, type_: type[_T], value: object) -> _T: + """Strict validation that the given value matches the expected type""" + if inspect.isclass(type_) and issubclass(type_, pydantic.BaseModel): + return cast(_T, parse_obj(type_, value)) + + return cast(_T, _validate_non_model_type(type_=type_, value=value)) + + +def set_pydantic_config(typ: Any, config: pydantic.ConfigDict) -> None: + """Add a pydantic config for the given type. + + Note: this is a no-op on Pydantic v1. + """ + setattr(typ, "__pydantic_config__", config) # noqa: B010 + + +# our use of subclassing here causes weirdness for type checkers, +# so we just pretend that we don't subclass +if TYPE_CHECKING: + GenericModel = BaseModel +else: + + class GenericModel(BaseGenericModel, BaseModel): + pass + + +if not PYDANTIC_V1: + from pydantic import TypeAdapter as _TypeAdapter + + _CachedTypeAdapter = cast("TypeAdapter[object]", lru_cache(maxsize=None)(_TypeAdapter)) + + if TYPE_CHECKING: + from pydantic import TypeAdapter + else: + TypeAdapter = _CachedTypeAdapter + + def _validate_non_model_type(*, type_: type[_T], value: object) -> _T: + return TypeAdapter(type_).validate_python(value) + +elif not TYPE_CHECKING: # TODO: condition is weird + + class RootModel(GenericModel, Generic[_T]): + """Used as a placeholder to easily convert runtime types to a Pydantic format + to provide validation. + + For example: + ```py + validated = RootModel[int](__root__="5").__root__ + # validated: 5 + ``` + """ + + __root__: _T + + def _validate_non_model_type(*, type_: type[_T], value: object) -> _T: + model = _create_pydantic_model(type_).validate(value) + return cast(_T, model.__root__) + + def _create_pydantic_model(type_: _T) -> Type[RootModel[_T]]: + return RootModel[type_] # type: ignore + + +class SecurityOptions(TypedDict, total=False): + api_key_auth: bool + bearer_auth: bool + + +class FinalRequestOptionsInput(TypedDict, total=False): + method: Required[str] + url: Required[str] + params: Query + headers: Headers + max_retries: int + timeout: float | Timeout | None + files: HttpxRequestFiles | None + idempotency_key: str + content: Union[bytes, bytearray, IO[bytes], Iterable[bytes], AsyncIterable[bytes], None] + json_data: Body + extra_json: AnyMapping + follow_redirects: bool + security: SecurityOptions + + +@final +class FinalRequestOptions(pydantic.BaseModel): + method: str + url: str + params: Query = {} + headers: Union[Headers, NotGiven] = NotGiven() + max_retries: Union[int, NotGiven] = NotGiven() + timeout: Union[float, Timeout, None, NotGiven] = NotGiven() + files: Union[HttpxRequestFiles, None] = None + idempotency_key: Union[str, None] = None + post_parser: Union[Callable[[Any], Any], NotGiven] = NotGiven() + follow_redirects: Union[bool, None] = None + security: SecurityOptions = { + "api_key_auth": True, + "bearer_auth": True, + } + + content: Union[bytes, bytearray, IO[bytes], Iterable[bytes], AsyncIterable[bytes], None] = None + # It should be noted that we cannot use `json` here as that would override + # a BaseModel method in an incompatible fashion. + json_data: Union[Body, None] = None + extra_json: Union[AnyMapping, None] = None + + if PYDANTIC_V1: + + class Config(pydantic.BaseConfig): # pyright: ignore[reportDeprecated] + arbitrary_types_allowed: bool = True + else: + model_config: ClassVar[ConfigDict] = ConfigDict(arbitrary_types_allowed=True) + + def get_max_retries(self, max_retries: int) -> int: + if isinstance(self.max_retries, NotGiven): + return max_retries + return self.max_retries + + def _strip_raw_response_header(self) -> None: + if not is_given(self.headers): + return + + if self.headers.get(RAW_RESPONSE_HEADER): + self.headers = {**self.headers} + self.headers.pop(RAW_RESPONSE_HEADER) + + # override the `construct` method so that we can run custom transformations. + # this is necessary as we don't want to do any actual runtime type checking + # (which means we can't use validators) but we do want to ensure that `NotGiven` + # values are not present + # + # type ignore required because we're adding explicit types to `**values` + @classmethod + def construct( # type: ignore + cls, + _fields_set: set[str] | None = None, + **values: Unpack[FinalRequestOptionsInput], + ) -> FinalRequestOptions: + kwargs: dict[str, Any] = { + # we unconditionally call `strip_not_given` on any value + # as it will just ignore any non-mapping types + key: strip_not_given(value) + for key, value in values.items() + } + if PYDANTIC_V1: + return cast(FinalRequestOptions, super().construct(_fields_set, **kwargs)) # pyright: ignore[reportDeprecated] + return super().model_construct(_fields_set, **kwargs) + + if not TYPE_CHECKING: + # type checkers incorrectly complain about this assignment + model_construct = construct diff --git a/src/_qs.py b/src/_qs.py new file mode 100644 index 0000000..4127c19 --- /dev/null +++ b/src/_qs.py @@ -0,0 +1,149 @@ +from __future__ import annotations + +from typing import Any, List, Tuple, Union, Mapping, TypeVar +from urllib.parse import parse_qs, urlencode +from typing_extensions import get_args + +from ._types import NotGiven, ArrayFormat, NestedFormat, not_given +from ._utils import flatten + +_T = TypeVar("_T") + +PrimitiveData = Union[str, int, float, bool, None] +# this should be Data = Union[PrimitiveData, "List[Data]", "Tuple[Data]", "Mapping[str, Data]"] +# https://github.com/microsoft/pyright/issues/3555 +Data = Union[PrimitiveData, List[Any], Tuple[Any], "Mapping[str, Any]"] +Params = Mapping[str, Data] + + +class Querystring: + array_format: ArrayFormat + nested_format: NestedFormat + + def __init__( + self, + *, + array_format: ArrayFormat = "repeat", + nested_format: NestedFormat = "brackets", + ) -> None: + self.array_format = array_format + self.nested_format = nested_format + + def parse(self, query: str) -> Mapping[str, object]: + # Note: custom format syntax is not supported yet + return parse_qs(query) + + def stringify( + self, + params: Params, + *, + array_format: ArrayFormat | NotGiven = not_given, + nested_format: NestedFormat | NotGiven = not_given, + ) -> str: + return urlencode( + self.stringify_items( + params, + array_format=array_format, + nested_format=nested_format, + ) + ) + + def stringify_items( + self, + params: Params, + *, + array_format: ArrayFormat | NotGiven = not_given, + nested_format: NestedFormat | NotGiven = not_given, + ) -> list[tuple[str, str]]: + opts = Options( + qs=self, + array_format=array_format, + nested_format=nested_format, + ) + return flatten([self._stringify_item(key, value, opts) for key, value in params.items()]) + + def _stringify_item( + self, + key: str, + value: Data, + opts: Options, + ) -> list[tuple[str, str]]: + if isinstance(value, Mapping): + items: list[tuple[str, str]] = [] + nested_format = opts.nested_format + for subkey, subvalue in value.items(): + items.extend( + self._stringify_item( + # TODO: error if unknown format + f"{key}.{subkey}" if nested_format == "dots" else f"{key}[{subkey}]", + subvalue, + opts, + ) + ) + return items + + if isinstance(value, (list, tuple)): + array_format = opts.array_format + if array_format == "comma": + return [ + ( + key, + ",".join(self._primitive_value_to_str(item) for item in value if item is not None), + ), + ] + elif array_format == "repeat": + items = [] + for item in value: + items.extend(self._stringify_item(key, item, opts)) + return items + elif array_format == "indices": + items = [] + for i, item in enumerate(value): + items.extend(self._stringify_item(f"{key}[{i}]", item, opts)) + return items + elif array_format == "brackets": + items = [] + key = key + "[]" + for item in value: + items.extend(self._stringify_item(key, item, opts)) + return items + else: + raise NotImplementedError( + f"Unknown array_format value: {array_format}, choose from {', '.join(get_args(ArrayFormat))}" + ) + + serialised = self._primitive_value_to_str(value) + if not serialised: + return [] + return [(key, serialised)] + + def _primitive_value_to_str(self, value: PrimitiveData) -> str: + # copied from httpx + if value is True: + return "true" + elif value is False: + return "false" + elif value is None: + return "" + return str(value) + + +_qs = Querystring() +parse = _qs.parse +stringify = _qs.stringify +stringify_items = _qs.stringify_items + + +class Options: + array_format: ArrayFormat + nested_format: NestedFormat + + def __init__( + self, + qs: Querystring = _qs, + *, + array_format: ArrayFormat | NotGiven = not_given, + nested_format: NestedFormat | NotGiven = not_given, + ) -> None: + self.array_format = qs.array_format if isinstance(array_format, NotGiven) else array_format + self.nested_format = qs.nested_format if isinstance(nested_format, NotGiven) else nested_format diff --git a/src/_resource.py b/src/_resource.py new file mode 100644 index 0000000..975eb18 --- /dev/null +++ b/src/_resource.py @@ -0,0 +1,43 @@ +# File generated from our OpenAPI spec by Scalar. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import time +from typing import TYPE_CHECKING + +import anyio + +if TYPE_CHECKING: + from ._client import ScalarApi, AsyncScalarApi + + +class SyncAPIResource: + _client: ScalarApi + + def __init__(self, client: ScalarApi) -> None: + self._client = client + self._get = client.get + self._post = client.post + self._patch = client.patch + self._put = client.put + self._delete = client.delete + self._get_api_list = client.get_api_list + + def _sleep(self, seconds: float) -> None: + time.sleep(seconds) + + +class AsyncAPIResource: + _client: AsyncScalarApi + + def __init__(self, client: AsyncScalarApi) -> None: + self._client = client + self._get = client.get + self._post = client.post + self._patch = client.patch + self._put = client.put + self._delete = client.delete + self._get_api_list = client.get_api_list + + async def _sleep(self, seconds: float) -> None: + await anyio.sleep(seconds) diff --git a/src/_response.py b/src/_response.py new file mode 100644 index 0000000..480d8a9 --- /dev/null +++ b/src/_response.py @@ -0,0 +1,832 @@ +from __future__ import annotations + +import os +import inspect +import logging +import datetime +import functools +from types import TracebackType +from typing import ( + TYPE_CHECKING, + Any, + Union, + Generic, + TypeVar, + Callable, + Iterator, + AsyncIterator, + cast, + overload, +) +from typing_extensions import Awaitable, ParamSpec, override, get_origin + +import anyio +import httpx +import pydantic + +from ._types import NoneType +from ._utils import is_given, extract_type_arg, is_annotated_type, is_type_alias_type, extract_type_var_from_base +from ._models import BaseModel, is_basemodel +from ._constants import RAW_RESPONSE_HEADER, OVERRIDE_CAST_TO_HEADER +from ._streaming import Stream, AsyncStream, is_stream_class_type, extract_stream_chunk_type +from ._exceptions import ScalarApiError, APIResponseValidationError + +if TYPE_CHECKING: + from ._models import FinalRequestOptions + from ._base_client import BaseClient + + +P = ParamSpec("P") +R = TypeVar("R") +_T = TypeVar("_T") +_APIResponseT = TypeVar("_APIResponseT", bound="APIResponse[Any]") +_AsyncAPIResponseT = TypeVar("_AsyncAPIResponseT", bound="AsyncAPIResponse[Any]") + +log: logging.Logger = logging.getLogger(__name__) + + +class BaseAPIResponse(Generic[R]): + _cast_to: type[R] + _client: BaseClient[Any, Any] + _parsed_by_type: dict[type[Any], Any] + _is_sse_stream: bool + _stream_cls: type[Stream[Any]] | type[AsyncStream[Any]] | None + _options: FinalRequestOptions + + http_response: httpx.Response + + retries_taken: int + """The number of retries made. If no retries happened this will be `0`""" + + def __init__( + self, + *, + raw: httpx.Response, + cast_to: type[R], + client: BaseClient[Any, Any], + stream: bool, + stream_cls: type[Stream[Any]] | type[AsyncStream[Any]] | None, + options: FinalRequestOptions, + retries_taken: int = 0, + ) -> None: + self._cast_to = cast_to + self._client = client + self._parsed_by_type = {} + self._is_sse_stream = stream + self._stream_cls = stream_cls + self._options = options + self.http_response = raw + self.retries_taken = retries_taken + + @property + def headers(self) -> httpx.Headers: + return self.http_response.headers + + @property + def http_request(self) -> httpx.Request: + """Returns the httpx Request instance associated with the current response.""" + return self.http_response.request + + @property + def status_code(self) -> int: + return self.http_response.status_code + + @property + def url(self) -> httpx.URL: + """Returns the URL for which the request was made.""" + return self.http_response.url + + @property + def method(self) -> str: + return self.http_request.method + + @property + def http_version(self) -> str: + return self.http_response.http_version + + @property + def elapsed(self) -> datetime.timedelta: + """The time taken for the complete request/response cycle to complete.""" + return self.http_response.elapsed + + @property + def is_closed(self) -> bool: + """Whether or not the response body has been closed. + + If this is False then there is response data that has not been read yet. + You must either fully consume the response body or call `.close()` + before discarding the response to prevent resource leaks. + """ + return self.http_response.is_closed + + @override + def __repr__(self) -> str: + return ( + f"<{self.__class__.__name__} [{self.status_code} {self.http_response.reason_phrase}] type={self._cast_to}>" + ) + + def _parse(self, *, to: type[_T] | None = None) -> R | _T: + cast_to = to if to is not None else self._cast_to + + # unwrap `TypeAlias('Name', T)` -> `T` + if is_type_alias_type(cast_to): + cast_to = cast_to.__value__ # type: ignore[unreachable] + + # unwrap `Annotated[T, ...]` -> `T` + if cast_to and is_annotated_type(cast_to): + cast_to = extract_type_arg(cast_to, 0) + + origin = get_origin(cast_to) or cast_to + + if self._is_sse_stream: + if to: + if not is_stream_class_type(to): + raise TypeError(f"Expected custom parse type to be a subclass of {Stream} or {AsyncStream}") + + return cast( + _T, + to( + cast_to=extract_stream_chunk_type( + to, + failure_message="Expected custom stream type to be passed with a type argument, e.g. Stream[ChunkType]", + ), + response=self.http_response, + client=cast(Any, self._client), + options=self._options, + ), + ) + + if self._stream_cls: + return cast( + R, + self._stream_cls( + cast_to=extract_stream_chunk_type(self._stream_cls), + response=self.http_response, + client=cast(Any, self._client), + options=self._options, + ), + ) + + stream_cls = cast("type[Stream[Any]] | type[AsyncStream[Any]] | None", self._client._default_stream_cls) + if stream_cls is None: + raise MissingStreamClassError() + + return cast( + R, + stream_cls( + cast_to=cast_to, + response=self.http_response, + client=cast(Any, self._client), + options=self._options, + ), + ) + + if cast_to is None or cast_to is NoneType: + return cast(R, None) + + response = self.http_response + if cast_to == str: + return cast(R, response.text) + + if cast_to == bytes: + return cast(R, response.content) + + if cast_to == int: + return cast(R, int(response.text)) + + if cast_to == float: + return cast(R, float(response.text)) + + if cast_to == bool: + return cast(R, response.text.lower() == "true") + + if origin == APIResponse: + raise RuntimeError("Unexpected state - cast_to is `APIResponse`") + + if inspect.isclass(origin) and issubclass(origin, httpx.Response): + # Because of the invariance of our ResponseT TypeVar, users can subclass httpx.Response + # and pass that class to our request functions. We cannot change the variance to be either + # covariant or contravariant as that makes our usage of ResponseT illegal. We could construct + # the response class ourselves but that is something that should be supported directly in httpx + # as it would be easy to incorrectly construct the Response object due to the multitude of arguments. + if cast_to != httpx.Response: + raise ValueError(f"Subclasses of httpx.Response cannot be passed to `cast_to`") + return cast(R, response) + + origin_is_class = inspect.isclass(origin) + origin_is_base_model = origin_is_class and issubclass(origin, BaseModel) + + if origin_is_class and not origin_is_base_model and issubclass(origin, pydantic.BaseModel): + raise TypeError( + "Pydantic models must subclass our base model type, e.g. `from scalar_api import BaseModel`" + ) + + if ( + cast_to is not object + and not origin is list + and not origin is dict + and not origin is Union + and not origin_is_base_model + ): + raise RuntimeError( + f"Unsupported type, expected {cast_to} to be a subclass of {BaseModel}, {dict}, {list}, {Union}, {NoneType}, {str} or {httpx.Response}." + ) + + # split is required to handle cases where additional information is included + # in the response, e.g. application/json; charset=utf-8 + content_type, *_ = response.headers.get("content-type", "*").split(";") + if not content_type.endswith("json"): + if is_basemodel(cast_to): + try: + data = response.json() + except Exception as exc: + log.debug("Could not read JSON from response data due to %s - %s", type(exc), exc) + else: + return self._client._process_response_data( + data=data, + cast_to=cast_to, # type: ignore + response=response, + ) + + if self._client._strict_response_validation: + raise APIResponseValidationError( + response=response, + message=f"Expected Content-Type response header to be `application/json` but received `{content_type}` instead.", + body=response.text, + ) + + # If the API responds with content that isn't JSON then we just return + # the (decoded) text without performing any parsing so that you can still + # handle the response however you need to. + return response.text # type: ignore + + data = response.json() + + return self._client._process_response_data( + data=data, + cast_to=cast_to, # type: ignore + response=response, + ) + + +class APIResponse(BaseAPIResponse[R]): + @overload + def parse(self, *, to: type[_T]) -> _T: ... + + @overload + def parse(self) -> R: ... + + def parse(self, *, to: type[_T] | None = None) -> R | _T: + """Returns the rich python representation of this response's data. + + For lower-level control, see `.read()`, `.json()`, `.iter_bytes()`. + + You can customise the type that the response is parsed into through + the `to` argument, e.g. + + ```py + from scalar_api import BaseModel + + + class MyModel(BaseModel): + foo: str + + + obj = response.parse(to=MyModel) + print(obj.foo) + ``` + + We support parsing: + - `BaseModel` + - `dict` + - `list` + - `Union` + - `str` + - `int` + - `float` + - `httpx.Response` + """ + cache_key = to if to is not None else self._cast_to + cached = self._parsed_by_type.get(cache_key) + if cached is not None: + return cached # type: ignore[no-any-return] + + if not self._is_sse_stream: + self.read() + + parsed = self._parse(to=to) + if is_given(self._options.post_parser): + parsed = self._options.post_parser(parsed) + + self._parsed_by_type[cache_key] = parsed + return parsed + + def read(self) -> bytes: + """Read and return the binary response content.""" + try: + return self.http_response.read() + except httpx.StreamConsumed as exc: + # The default error raised by httpx isn't very + # helpful in our case so we re-raise it with + # a different error message. + raise StreamAlreadyConsumed() from exc + + def text(self) -> str: + """Read and decode the response content into a string.""" + self.read() + return self.http_response.text + + def json(self) -> object: + """Read and decode the JSON response content.""" + self.read() + return self.http_response.json() + + def close(self) -> None: + """Close the response and release the connection. + + Automatically called if the response body is read to completion. + """ + self.http_response.close() + + def iter_bytes(self, chunk_size: int | None = None) -> Iterator[bytes]: + """ + A byte-iterator over the decoded response content. + + This automatically handles gzip, deflate and brotli encoded responses. + """ + for chunk in self.http_response.iter_bytes(chunk_size): + yield chunk + + def iter_text(self, chunk_size: int | None = None) -> Iterator[str]: + """A str-iterator over the decoded response content + that handles both gzip, deflate, etc but also detects the content's + string encoding. + """ + for chunk in self.http_response.iter_text(chunk_size): + yield chunk + + def iter_lines(self) -> Iterator[str]: + """Like `iter_text()` but will only yield chunks for each line""" + for chunk in self.http_response.iter_lines(): + yield chunk + + +class AsyncAPIResponse(BaseAPIResponse[R]): + @overload + async def parse(self, *, to: type[_T]) -> _T: ... + + @overload + async def parse(self) -> R: ... + + async def parse(self, *, to: type[_T] | None = None) -> R | _T: + """Returns the rich python representation of this response's data. + + For lower-level control, see `.read()`, `.json()`, `.iter_bytes()`. + + You can customise the type that the response is parsed into through + the `to` argument, e.g. + + ```py + from scalar_api import BaseModel + + + class MyModel(BaseModel): + foo: str + + + obj = response.parse(to=MyModel) + print(obj.foo) + ``` + + We support parsing: + - `BaseModel` + - `dict` + - `list` + - `Union` + - `str` + - `httpx.Response` + """ + cache_key = to if to is not None else self._cast_to + cached = self._parsed_by_type.get(cache_key) + if cached is not None: + return cached # type: ignore[no-any-return] + + if not self._is_sse_stream: + await self.read() + + parsed = self._parse(to=to) + if is_given(self._options.post_parser): + parsed = self._options.post_parser(parsed) + + self._parsed_by_type[cache_key] = parsed + return parsed + + async def read(self) -> bytes: + """Read and return the binary response content.""" + try: + return await self.http_response.aread() + except httpx.StreamConsumed as exc: + # the default error raised by httpx isn't very + # helpful in our case so we re-raise it with + # a different error message + raise StreamAlreadyConsumed() from exc + + async def text(self) -> str: + """Read and decode the response content into a string.""" + await self.read() + return self.http_response.text + + async def json(self) -> object: + """Read and decode the JSON response content.""" + await self.read() + return self.http_response.json() + + async def close(self) -> None: + """Close the response and release the connection. + + Automatically called if the response body is read to completion. + """ + await self.http_response.aclose() + + async def iter_bytes(self, chunk_size: int | None = None) -> AsyncIterator[bytes]: + """ + A byte-iterator over the decoded response content. + + This automatically handles gzip, deflate and brotli encoded responses. + """ + async for chunk in self.http_response.aiter_bytes(chunk_size): + yield chunk + + async def iter_text(self, chunk_size: int | None = None) -> AsyncIterator[str]: + """A str-iterator over the decoded response content + that handles both gzip, deflate, etc but also detects the content's + string encoding. + """ + async for chunk in self.http_response.aiter_text(chunk_size): + yield chunk + + async def iter_lines(self) -> AsyncIterator[str]: + """Like `iter_text()` but will only yield chunks for each line""" + async for chunk in self.http_response.aiter_lines(): + yield chunk + + +class BinaryAPIResponse(APIResponse[bytes]): + """Subclass of APIResponse providing helpers for dealing with binary data. + + Note: If you want to stream the response data instead of eagerly reading it + all at once then you should use `.with_streaming_response` when making + the API request, e.g. `.with_streaming_response.get_binary_response()` + """ + + def write_to_file( + self, + file: str | os.PathLike[str], + ) -> None: + """Write the output to the given file. + + Accepts a filename or any path-like object, e.g. pathlib.Path + + Note: if you want to stream the data to the file instead of writing + all at once then you should use `.with_streaming_response` when making + the API request, e.g. `.with_streaming_response.get_binary_response()` + """ + with open(file, mode="wb") as f: + for data in self.iter_bytes(): + f.write(data) + + +class AsyncBinaryAPIResponse(AsyncAPIResponse[bytes]): + """Subclass of APIResponse providing helpers for dealing with binary data. + + Note: If you want to stream the response data instead of eagerly reading it + all at once then you should use `.with_streaming_response` when making + the API request, e.g. `.with_streaming_response.get_binary_response()` + """ + + async def write_to_file( + self, + file: str | os.PathLike[str], + ) -> None: + """Write the output to the given file. + + Accepts a filename or any path-like object, e.g. pathlib.Path + + Note: if you want to stream the data to the file instead of writing + all at once then you should use `.with_streaming_response` when making + the API request, e.g. `.with_streaming_response.get_binary_response()` + """ + path = anyio.Path(file) + async with await path.open(mode="wb") as f: + async for data in self.iter_bytes(): + await f.write(data) + + +class StreamedBinaryAPIResponse(APIResponse[bytes]): + def stream_to_file( + self, + file: str | os.PathLike[str], + *, + chunk_size: int | None = None, + ) -> None: + """Streams the output to the given file. + + Accepts a filename or any path-like object, e.g. pathlib.Path + """ + with open(file, mode="wb") as f: + for data in self.iter_bytes(chunk_size): + f.write(data) + + +class AsyncStreamedBinaryAPIResponse(AsyncAPIResponse[bytes]): + async def stream_to_file( + self, + file: str | os.PathLike[str], + *, + chunk_size: int | None = None, + ) -> None: + """Streams the output to the given file. + + Accepts a filename or any path-like object, e.g. pathlib.Path + """ + path = anyio.Path(file) + async with await path.open(mode="wb") as f: + async for data in self.iter_bytes(chunk_size): + await f.write(data) + + +class MissingStreamClassError(TypeError): + def __init__(self) -> None: + super().__init__( + "The `stream` argument was set to `True` but the `stream_cls` argument was not given. See `scalar_api._streaming` for reference", + ) + + +class StreamAlreadyConsumed(ScalarApiError): + """ + Attempted to read or stream content, but the content has already + been streamed. + + This can happen if you use a method like `.iter_lines()` and then attempt + to read th entire response body afterwards, e.g. + + ```py + response = await client.post(...) + async for line in response.iter_lines(): + ... # do something with `line` + + content = await response.read() + # ^ error + ``` + + If you want this behaviour you'll need to either manually accumulate the response + content or call `await response.read()` before iterating over the stream. + """ + + def __init__(self) -> None: + message = ( + "Attempted to read or stream some content, but the content has " + "already been streamed. " + "This could be due to attempting to stream the response " + "content more than once." + "\n\n" + "You can fix this by manually accumulating the response content while streaming " + "or by calling `.read()` before starting to stream." + ) + super().__init__(message) + + +class ResponseContextManager(Generic[_APIResponseT]): + """Context manager for ensuring that a request is not made + until it is entered and that the response will always be closed + when the context manager exits + """ + + def __init__(self, request_func: Callable[[], _APIResponseT]) -> None: + self._request_func = request_func + self.__response: _APIResponseT | None = None + + def __enter__(self) -> _APIResponseT: + self.__response = self._request_func() + return self.__response + + def __exit__( + self, + exc_type: type[BaseException] | None, + exc: BaseException | None, + exc_tb: TracebackType | None, + ) -> None: + if self.__response is not None: + self.__response.close() + + +class AsyncResponseContextManager(Generic[_AsyncAPIResponseT]): + """Context manager for ensuring that a request is not made + until it is entered and that the response will always be closed + when the context manager exits + """ + + def __init__(self, api_request: Awaitable[_AsyncAPIResponseT]) -> None: + self._api_request = api_request + self.__response: _AsyncAPIResponseT | None = None + + async def __aenter__(self) -> _AsyncAPIResponseT: + self.__response = await self._api_request + return self.__response + + async def __aexit__( + self, + exc_type: type[BaseException] | None, + exc: BaseException | None, + exc_tb: TracebackType | None, + ) -> None: + if self.__response is not None: + await self.__response.close() + + +def to_streamed_response_wrapper(func: Callable[P, R]) -> Callable[P, ResponseContextManager[APIResponse[R]]]: + """Higher order function that takes one of our bound API methods and wraps it + to support streaming and returning the raw `APIResponse` object directly. + """ + + @functools.wraps(func) + def wrapped(*args: P.args, **kwargs: P.kwargs) -> ResponseContextManager[APIResponse[R]]: + extra_headers: dict[str, str] = {**(cast(Any, kwargs.get("extra_headers")) or {})} + extra_headers[RAW_RESPONSE_HEADER] = "stream" + + kwargs["extra_headers"] = extra_headers + + make_request = functools.partial(func, *args, **kwargs) + + return ResponseContextManager(cast(Callable[[], APIResponse[R]], make_request)) + + return wrapped + + +def async_to_streamed_response_wrapper( + func: Callable[P, Awaitable[R]], +) -> Callable[P, AsyncResponseContextManager[AsyncAPIResponse[R]]]: + """Higher order function that takes one of our bound API methods and wraps it + to support streaming and returning the raw `APIResponse` object directly. + """ + + @functools.wraps(func) + def wrapped(*args: P.args, **kwargs: P.kwargs) -> AsyncResponseContextManager[AsyncAPIResponse[R]]: + extra_headers: dict[str, str] = {**(cast(Any, kwargs.get("extra_headers")) or {})} + extra_headers[RAW_RESPONSE_HEADER] = "stream" + + kwargs["extra_headers"] = extra_headers + + make_request = func(*args, **kwargs) + + return AsyncResponseContextManager(cast(Awaitable[AsyncAPIResponse[R]], make_request)) + + return wrapped + + +def to_custom_streamed_response_wrapper( + func: Callable[P, object], + response_cls: type[_APIResponseT], +) -> Callable[P, ResponseContextManager[_APIResponseT]]: + """Higher order function that takes one of our bound API methods and an `APIResponse` class + and wraps the method to support streaming and returning the given response class directly. + + Note: the given `response_cls` *must* be concrete, e.g. `class BinaryAPIResponse(APIResponse[bytes])` + """ + + @functools.wraps(func) + def wrapped(*args: P.args, **kwargs: P.kwargs) -> ResponseContextManager[_APIResponseT]: + extra_headers: dict[str, Any] = {**(cast(Any, kwargs.get("extra_headers")) or {})} + extra_headers[RAW_RESPONSE_HEADER] = "stream" + extra_headers[OVERRIDE_CAST_TO_HEADER] = response_cls + + kwargs["extra_headers"] = extra_headers + + make_request = functools.partial(func, *args, **kwargs) + + return ResponseContextManager(cast(Callable[[], _APIResponseT], make_request)) + + return wrapped + + +def async_to_custom_streamed_response_wrapper( + func: Callable[P, Awaitable[object]], + response_cls: type[_AsyncAPIResponseT], +) -> Callable[P, AsyncResponseContextManager[_AsyncAPIResponseT]]: + """Higher order function that takes one of our bound API methods and an `APIResponse` class + and wraps the method to support streaming and returning the given response class directly. + + Note: the given `response_cls` *must* be concrete, e.g. `class BinaryAPIResponse(APIResponse[bytes])` + """ + + @functools.wraps(func) + def wrapped(*args: P.args, **kwargs: P.kwargs) -> AsyncResponseContextManager[_AsyncAPIResponseT]: + extra_headers: dict[str, Any] = {**(cast(Any, kwargs.get("extra_headers")) or {})} + extra_headers[RAW_RESPONSE_HEADER] = "stream" + extra_headers[OVERRIDE_CAST_TO_HEADER] = response_cls + + kwargs["extra_headers"] = extra_headers + + make_request = func(*args, **kwargs) + + return AsyncResponseContextManager(cast(Awaitable[_AsyncAPIResponseT], make_request)) + + return wrapped + + +def to_raw_response_wrapper(func: Callable[P, R]) -> Callable[P, APIResponse[R]]: + """Higher order function that takes one of our bound API methods and wraps it + to support returning the raw `APIResponse` object directly. + """ + + @functools.wraps(func) + def wrapped(*args: P.args, **kwargs: P.kwargs) -> APIResponse[R]: + extra_headers: dict[str, str] = {**(cast(Any, kwargs.get("extra_headers")) or {})} + extra_headers[RAW_RESPONSE_HEADER] = "raw" + + kwargs["extra_headers"] = extra_headers + + return cast(APIResponse[R], func(*args, **kwargs)) + + return wrapped + + +def async_to_raw_response_wrapper(func: Callable[P, Awaitable[R]]) -> Callable[P, Awaitable[AsyncAPIResponse[R]]]: + """Higher order function that takes one of our bound API methods and wraps it + to support returning the raw `APIResponse` object directly. + """ + + @functools.wraps(func) + async def wrapped(*args: P.args, **kwargs: P.kwargs) -> AsyncAPIResponse[R]: + extra_headers: dict[str, str] = {**(cast(Any, kwargs.get("extra_headers")) or {})} + extra_headers[RAW_RESPONSE_HEADER] = "raw" + + kwargs["extra_headers"] = extra_headers + + return cast(AsyncAPIResponse[R], await func(*args, **kwargs)) + + return wrapped + + +def to_custom_raw_response_wrapper( + func: Callable[P, object], + response_cls: type[_APIResponseT], +) -> Callable[P, _APIResponseT]: + """Higher order function that takes one of our bound API methods and an `APIResponse` class + and wraps the method to support returning the given response class directly. + + Note: the given `response_cls` *must* be concrete, e.g. `class BinaryAPIResponse(APIResponse[bytes])` + """ + + @functools.wraps(func) + def wrapped(*args: P.args, **kwargs: P.kwargs) -> _APIResponseT: + extra_headers: dict[str, Any] = {**(cast(Any, kwargs.get("extra_headers")) or {})} + extra_headers[RAW_RESPONSE_HEADER] = "raw" + extra_headers[OVERRIDE_CAST_TO_HEADER] = response_cls + + kwargs["extra_headers"] = extra_headers + + return cast(_APIResponseT, func(*args, **kwargs)) + + return wrapped + + +def async_to_custom_raw_response_wrapper( + func: Callable[P, Awaitable[object]], + response_cls: type[_AsyncAPIResponseT], +) -> Callable[P, Awaitable[_AsyncAPIResponseT]]: + """Higher order function that takes one of our bound API methods and an `APIResponse` class + and wraps the method to support returning the given response class directly. + + Note: the given `response_cls` *must* be concrete, e.g. `class BinaryAPIResponse(APIResponse[bytes])` + """ + + @functools.wraps(func) + def wrapped(*args: P.args, **kwargs: P.kwargs) -> Awaitable[_AsyncAPIResponseT]: + extra_headers: dict[str, Any] = {**(cast(Any, kwargs.get("extra_headers")) or {})} + extra_headers[RAW_RESPONSE_HEADER] = "raw" + extra_headers[OVERRIDE_CAST_TO_HEADER] = response_cls + + kwargs["extra_headers"] = extra_headers + + return cast(Awaitable[_AsyncAPIResponseT], func(*args, **kwargs)) + + return wrapped + + +def extract_response_type(typ: type[BaseAPIResponse[Any]]) -> type: + """Given a type like `APIResponse[T]`, returns the generic type variable `T`. + + This also handles the case where a concrete subclass is given, e.g. + ```py + class MyResponse(APIResponse[bytes]): + ... + + extract_response_type(MyResponse) -> bytes + ``` + """ + return extract_type_var_from_base( + typ, + generic_bases=cast("tuple[type, ...]", (BaseAPIResponse, APIResponse, AsyncAPIResponse)), + index=0, + ) diff --git a/src/_send_queue.py b/src/_send_queue.py new file mode 100644 index 0000000..3140d45 --- /dev/null +++ b/src/_send_queue.py @@ -0,0 +1,90 @@ +# File generated from our OpenAPI spec by Scalar. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import typing +import threading + +from ._exceptions import WebSocketQueueFullError + + +class SendQueue: + """Bounded byte-size queue for outgoing WebSocket messages. + + Messages are stored as pre-serialized strings. The queue enforces a + maximum byte budget so that unbounded buffering cannot occur during + reconnection windows. + """ + + def __init__(self, max_bytes: int = 1_048_576) -> None: + self._queue: list[tuple[str, int]] = [] # (data, byte_length) + self._bytes: int = 0 + self._max_bytes = max_bytes + self._lock = threading.Lock() + + def enqueue(self, data: str) -> None: + """Append *data* to the queue. + + Raises :class:`WebSocketQueueFullError` if the message would + exceed the byte-size limit. + """ + byte_length = len(data.encode("utf-8")) + with self._lock: + if self._bytes + byte_length > self._max_bytes: + raise WebSocketQueueFullError("send queue is full, message discarded") + self._queue.append((data, byte_length)) + self._bytes += byte_length + + def flush_sync(self, send: typing.Callable[[str], object]) -> None: + """Send every queued message via *send*. + + If *send* raises, the failing message and all subsequent messages + are re-queued and the error is re-raised. + """ + with self._lock: + pending = list(self._queue) + self._queue.clear() + self._bytes = 0 + + for i, (data, _byte_length) in enumerate(pending): + try: + send(data) + except Exception: + with self._lock: + remaining = pending[i:] + self._queue = remaining + self._queue + self._bytes = sum(bl for _, bl in self._queue) + raise + + async def flush_async(self, send: typing.Callable[[str], typing.Awaitable[object]]) -> None: + """Async variant of :meth:`flush_sync`.""" + with self._lock: + pending = list(self._queue) + self._queue.clear() + self._bytes = 0 + + for i, (data, _byte_length) in enumerate(pending): + try: + await send(data) + except Exception: + with self._lock: + remaining = pending[i:] + self._queue = remaining + self._queue + self._bytes = sum(bl for _, bl in self._queue) + raise + + def drain(self) -> list[str]: + """Remove and return all queued messages.""" + with self._lock: + items = [data for data, _ in self._queue] + self._queue.clear() + self._bytes = 0 + return items + + def __len__(self) -> int: + with self._lock: + return len(self._queue) + + def __bool__(self) -> bool: + with self._lock: + return len(self._queue) > 0 diff --git a/src/_streaming.py b/src/_streaming.py new file mode 100644 index 0000000..8105558 --- /dev/null +++ b/src/_streaming.py @@ -0,0 +1,470 @@ +# Note: initially copied from https://github.com/florimondmanca/httpx-sse/blob/master/src/httpx_sse/_decoders.py +from __future__ import annotations + +import json +import inspect +from types import TracebackType +from typing import TYPE_CHECKING, Any, Generic, List, Mapping, Optional, Sequence, TypeVar, Union, Iterator, AsyncIterator, cast +from typing_extensions import Self, Protocol, TypeGuard, override, get_origin, runtime_checkable + +import httpx + +from ._utils import extract_type_var_from_base + +if TYPE_CHECKING: + from ._client import ScalarApi, AsyncScalarApi + from ._models import FinalRequestOptions + + +_T = TypeVar("_T") + + +# Mirrors `StreamingEventHandler` from the IR (`packages/ir-compiler/src/ +# types.ts`). The generated client emits its own `_streaming_handlers` +# list populated from `ctx.config.streaming.onEvent`; the runtime +# dispatch below honors `continue`, `ignore`, `error`, and `yield` +# actions the same way the TypeScript runtime does. When the client has +# no handlers we fall back to the generic "yield every data-bearing +# event" behavior so SDKs without a streaming config still work. +StreamingEventHandler = Mapping[str, Any] + + +def _event_type_matches(event: Optional[str], expected: Any) -> bool: + if expected is None: + return event is None + if isinstance(expected, (list, tuple)): + return (event or "") in expected + return expected is not None and event == expected + + +def _stream_handler_for_sse( + sse: "ServerSentEvent", + handlers: Optional[Sequence[StreamingEventHandler]], +) -> Optional[StreamingEventHandler]: + if not handlers: + return None + for handler in handlers: + if handler.get("kind") == "data": + prefix = handler.get("dataStartsWith") + if isinstance(prefix, str) and sse.data.startswith(prefix): + return handler + for handler in handlers: + kind = handler.get("kind") + if kind == "event" and _event_type_matches(sse.event, handler.get("eventType")): + return handler + if kind == "fallthrough": + return handler + return None + + +def _stream_error_message(sse: "ServerSentEvent", handler: StreamingEventHandler) -> tuple[Any, str]: + body: Any = sse.data + try: + body = sse.json() + except Exception: + body = sse.data + error_property = handler.get("errorProperty") + payload = body + if isinstance(payload, dict) and isinstance(error_property, str) and error_property in payload: + payload = payload[error_property] + return body, f"{payload}" if payload is not None else (sse.data or "Stream error") + + +class Stream(Generic[_T]): + """Provides the core interface to iterate over a synchronous stream response.""" + + response: httpx.Response + _options: Optional[FinalRequestOptions] = None + _decoder: SSEBytesDecoder + + def __init__( + self, + *, + cast_to: type[_T], + response: httpx.Response, + client: ScalarApi, + options: Optional[FinalRequestOptions] = None, + ) -> None: + self.response = response + self._cast_to = cast_to + self._client = client + self._options = options + self._decoder = client._make_sse_decoder() + self._iterator = self.__stream__() + + def __next__(self) -> _T: + return self._iterator.__next__() + + def __iter__(self) -> Iterator[_T]: + for item in self._iterator: + yield item + + def _iter_events(self) -> Iterator[ServerSentEvent]: + yield from self._decoder.iter_bytes(self.response.iter_bytes()) + + def __stream__(self) -> Iterator[_T]: + cast_to = cast(Any, self._cast_to) + response = self.response + process_data = self._client._process_response_data + iterator = self._iter_events() + handlers = getattr(self._client, "_streaming_handlers", None) + content_type = (response.headers.get("content-type") or "").lower() + is_jsonl = "json" in content_type and "event-stream" not in content_type + + try: + if is_jsonl: + # Newline-delimited JSON (`application/jsonl`, + # `application/x-jsonl`, etc.) has no SSE framing, so the + # `_decoder.iter_bytes` path above would never yield. We + # parse each non-empty line as one event so callers can + # iterate without caring whether the wire format is SSE + # or JSONL. + buffer = b"" + for chunk in response.iter_bytes(): + if not chunk: + continue + buffer += chunk + while b"\n" in buffer: + line, buffer = buffer.split(b"\n", 1) + text = line.decode("utf-8").strip() + if not text: + continue + yield process_data(data=json.loads(text), cast_to=cast_to, response=response) + tail = buffer.decode("utf-8").strip() + if tail: + yield process_data(data=json.loads(tail), cast_to=cast_to, response=response) + return + + for sse in iterator: + # Dispatch every SSE event through the + # config-derived handler list. With no handlers + # configured we fall back to "yield every data-bearing + # event" which matches the TypeScript runtime. + handler = _stream_handler_for_sse(sse, handlers) + action = handler.get("handle") if handler else None + if action in ("continue", "ignore"): + continue + if action == "error" and handler is not None: + body, err_msg = _stream_error_message(sse, handler) + raise self._client._make_status_error(err_msg, body=body, response=self.response) + if handlers and action != "yield": + continue + if not sse.data: + continue + try: + payload = sse.json() + except Exception: + payload = sse.data + yield process_data(data=payload, cast_to=cast_to, response=response) + finally: + # Ensure the response is closed even if the consumer doesn't read all data + response.close() + + def __enter__(self) -> Self: + return self + + def __exit__( + self, + exc_type: type[BaseException] | None, + exc: BaseException | None, + exc_tb: TracebackType | None, + ) -> None: + self.close() + + def close(self) -> None: + """ + Close the response and release the connection. + + Automatically called if the response body is read to completion. + """ + self.response.close() + + +class AsyncStream(Generic[_T]): + """Provides the core interface to iterate over an asynchronous stream response.""" + + response: httpx.Response + _options: Optional[FinalRequestOptions] = None + _decoder: SSEDecoder | SSEBytesDecoder + + def __init__( + self, + *, + cast_to: type[_T], + response: httpx.Response, + client: AsyncScalarApi, + options: Optional[FinalRequestOptions] = None, + ) -> None: + self.response = response + self._cast_to = cast_to + self._client = client + self._options = options + self._decoder = client._make_sse_decoder() + self._iterator = self.__stream__() + + async def __anext__(self) -> _T: + return await self._iterator.__anext__() + + async def __aiter__(self) -> AsyncIterator[_T]: + async for item in self._iterator: + yield item + + async def _iter_events(self) -> AsyncIterator[ServerSentEvent]: + async for sse in self._decoder.aiter_bytes(self.response.aiter_bytes()): + yield sse + + async def __stream__(self) -> AsyncIterator[_T]: + cast_to = cast(Any, self._cast_to) + response = self.response + process_data = self._client._process_response_data + iterator = self._iter_events() + handlers = getattr(self._client, "_streaming_handlers", None) + content_type = (response.headers.get("content-type") or "").lower() + is_jsonl = "json" in content_type and "event-stream" not in content_type + + try: + if is_jsonl: + # See the sync sibling for why JSONL gets its own branch. + buffer = b"" + async for chunk in response.aiter_bytes(): + if not chunk: + continue + buffer += chunk + while b"\n" in buffer: + line, buffer = buffer.split(b"\n", 1) + text = line.decode("utf-8").strip() + if not text: + continue + yield process_data(data=json.loads(text), cast_to=cast_to, response=response) + tail = buffer.decode("utf-8").strip() + if tail: + yield process_data(data=json.loads(tail), cast_to=cast_to, response=response) + return + + async for sse in iterator: + handler = _stream_handler_for_sse(sse, handlers) + action = handler.get("handle") if handler else None + if action in ("continue", "ignore"): + continue + if action == "error" and handler is not None: + body, err_msg = _stream_error_message(sse, handler) + raise self._client._make_status_error(err_msg, body=body, response=self.response) + if handlers and action != "yield": + continue + if not sse.data: + continue + try: + payload = sse.json() + except Exception: + payload = sse.data + yield process_data(data=payload, cast_to=cast_to, response=response) + finally: + # Ensure the response is closed even if the consumer doesn't read all data + await response.aclose() + + async def __aenter__(self) -> Self: + return self + + async def __aexit__( + self, + exc_type: type[BaseException] | None, + exc: BaseException | None, + exc_tb: TracebackType | None, + ) -> None: + await self.close() + + async def close(self) -> None: + """ + Close the response and release the connection. + + Automatically called if the response body is read to completion. + """ + await self.response.aclose() + + +class ServerSentEvent: + def __init__( + self, + *, + event: str | None = None, + data: str | None = None, + id: str | None = None, + retry: int | None = None, + ) -> None: + if data is None: + data = "" + + self._id = id + self._data = data + self._event = event or None + self._retry = retry + + @property + def event(self) -> str | None: + return self._event + + @property + def id(self) -> str | None: + return self._id + + @property + def retry(self) -> int | None: + return self._retry + + @property + def data(self) -> str: + return self._data + + def json(self) -> Any: + return json.loads(self.data) + + @override + def __repr__(self) -> str: + return f"ServerSentEvent(event={self.event}, data={self.data}, id={self.id}, retry={self.retry})" + + +class SSEDecoder: + _data: list[str] + _event: str | None + _retry: int | None + _last_event_id: str | None + + def __init__(self) -> None: + self._event = None + self._data = [] + self._last_event_id = None + self._retry = None + + def iter_bytes(self, iterator: Iterator[bytes]) -> Iterator[ServerSentEvent]: + """Given an iterator that yields raw binary data, iterate over it & yield every event encountered""" + for chunk in self._iter_chunks(iterator): + # Split before decoding so splitlines() only uses \r and \n + for raw_line in chunk.splitlines(): + line = raw_line.decode("utf-8") + sse = self.decode(line) + if sse: + yield sse + + def _iter_chunks(self, iterator: Iterator[bytes]) -> Iterator[bytes]: + """Given an iterator that yields raw binary data, iterate over it and yield individual SSE chunks""" + data = b"" + for chunk in iterator: + for line in chunk.splitlines(keepends=True): + data += line + if data.endswith((b"\r\r", b"\n\n", b"\r\n\r\n")): + yield data + data = b"" + if data: + yield data + + async def aiter_bytes(self, iterator: AsyncIterator[bytes]) -> AsyncIterator[ServerSentEvent]: + """Given an iterator that yields raw binary data, iterate over it & yield every event encountered""" + async for chunk in self._aiter_chunks(iterator): + # Split before decoding so splitlines() only uses \r and \n + for raw_line in chunk.splitlines(): + line = raw_line.decode("utf-8") + sse = self.decode(line) + if sse: + yield sse + + async def _aiter_chunks(self, iterator: AsyncIterator[bytes]) -> AsyncIterator[bytes]: + """Given an iterator that yields raw binary data, iterate over it and yield individual SSE chunks""" + data = b"" + async for chunk in iterator: + for line in chunk.splitlines(keepends=True): + data += line + if data.endswith((b"\r\r", b"\n\n", b"\r\n\r\n")): + yield data + data = b"" + if data: + yield data + + def decode(self, line: str) -> ServerSentEvent | None: + # See: https://html.spec.whatwg.org/multipage/server-sent-events.html#event-stream-interpretation # noqa: E501 + + if not line: + if not self._event and not self._data and not self._last_event_id and self._retry is None: + return None + + sse = ServerSentEvent( + event=self._event, + data="\n".join(self._data), + id=self._last_event_id, + retry=self._retry, + ) + + # NOTE: as per the SSE spec, do not reset last_event_id. + self._event = None + self._data = [] + self._retry = None + + return sse + + if line.startswith(":"): + return None + + fieldname, _, value = line.partition(":") + + if value.startswith(" "): + value = value[1:] + + if fieldname == "event": + self._event = value + elif fieldname == "data": + self._data.append(value) + elif fieldname == "id": + if "\0" in value: + pass + else: + self._last_event_id = value + elif fieldname == "retry": + try: + self._retry = int(value) + except (TypeError, ValueError): + pass + else: + pass # Field is ignored. + + return None + + +@runtime_checkable +class SSEBytesDecoder(Protocol): + def iter_bytes(self, iterator: Iterator[bytes]) -> Iterator[ServerSentEvent]: + """Given an iterator that yields raw binary data, iterate over it & yield every event encountered""" + ... + + def aiter_bytes(self, iterator: AsyncIterator[bytes]) -> AsyncIterator[ServerSentEvent]: + """Given an async iterator that yields raw binary data, iterate over it & yield every event encountered""" + ... + + +def is_stream_class_type(typ: type) -> TypeGuard[type[Stream[object]] | type[AsyncStream[object]]]: + """TypeGuard for determining whether or not the given type is a subclass of `Stream` / `AsyncStream`""" + origin = get_origin(typ) or typ + return inspect.isclass(origin) and issubclass(origin, (Stream, AsyncStream)) + + +def extract_stream_chunk_type( + stream_cls: type, + *, + failure_message: str | None = None, +) -> type: + """Given a type like `Stream[T]`, returns the generic type variable `T`. + + This also handles the case where a concrete subclass is given, e.g. + ```py + class MyStream(Stream[bytes]): + ... + + extract_stream_chunk_type(MyStream) -> bytes + ``` + """ + from ._base_client import Stream, AsyncStream + + return extract_type_var_from_base( + stream_cls, + index=0, + generic_bases=cast("tuple[type, ...]", (Stream, AsyncStream)), + failure_message=failure_message, + ) diff --git a/src/_types.py b/src/_types.py new file mode 100644 index 0000000..047012f --- /dev/null +++ b/src/_types.py @@ -0,0 +1,274 @@ +from __future__ import annotations + +from os import PathLike +from typing import ( + IO, + TYPE_CHECKING, + Any, + Dict, + List, + Type, + Tuple, + Union, + Mapping, + TypeVar, + Callable, + Iterable, + Iterator, + Optional, + Sequence, + AsyncIterable, +) +from typing_extensions import ( + Set, + Literal, + Protocol, + TypeAlias, + TypedDict, + SupportsIndex, + overload, + override, + runtime_checkable, +) + +import httpx +import pydantic +from httpx import URL, Proxy, Timeout, Response, BaseTransport, AsyncBaseTransport + +if TYPE_CHECKING: + from ._models import BaseModel, SecurityOptions + from ._response import APIResponse, AsyncAPIResponse + +Transport = BaseTransport +AsyncTransport = AsyncBaseTransport +Query = Mapping[str, object] +Body = object +AnyMapping = Mapping[str, object] +ModelT = TypeVar("ModelT", bound=pydantic.BaseModel) +_T = TypeVar("_T") + +ArrayFormat = Literal["comma", "repeat", "indices", "brackets"] +NestedFormat = Literal["dots", "brackets"] + + +# Approximates httpx internal ProxiesTypes and RequestFiles types +# while adding support for `PathLike` instances +ProxiesDict = Dict["str | URL", Union[None, str, URL, Proxy]] +ProxiesTypes = Union[str, Proxy, ProxiesDict] +if TYPE_CHECKING: + Base64FileInput = Union[IO[bytes], PathLike[str]] + FileContent = Union[IO[bytes], bytes, PathLike[str]] +else: + Base64FileInput = Union[IO[bytes], PathLike] + FileContent = Union[IO[bytes], bytes, PathLike] # PathLike is not subscriptable in Python 3.8. + + +# Used for sending raw binary data / streaming data in request bodies +# e.g. for file uploads without multipart encoding +BinaryTypes = Union[bytes, bytearray, IO[bytes], Iterable[bytes]] +AsyncBinaryTypes = Union[bytes, bytearray, IO[bytes], AsyncIterable[bytes]] + +FileTypes = Union[ + # file (or bytes) + FileContent, + # (filename, file (or bytes)) + Tuple[Optional[str], FileContent], + # (filename, file (or bytes), content_type) + Tuple[Optional[str], FileContent, Optional[str]], + # (filename, file (or bytes), content_type, headers) + Tuple[Optional[str], FileContent, Optional[str], Mapping[str, str]], +] +RequestFiles = Union[Mapping[str, FileTypes], Sequence[Tuple[str, FileTypes]]] + +# duplicate of the above but without our custom file support +HttpxFileContent = Union[IO[bytes], bytes] +HttpxFileTypes = Union[ + # file (or bytes) + HttpxFileContent, + # (filename, file (or bytes)) + Tuple[Optional[str], HttpxFileContent], + # (filename, file (or bytes), content_type) + Tuple[Optional[str], HttpxFileContent, Optional[str]], + # (filename, file (or bytes), content_type, headers) + Tuple[Optional[str], HttpxFileContent, Optional[str], Mapping[str, str]], +] +HttpxRequestFiles = Union[Mapping[str, HttpxFileTypes], Sequence[Tuple[str, HttpxFileTypes]]] + +# Workaround to support (cast_to: Type[ResponseT]) -> ResponseT +# where ResponseT includes `None`. In order to support directly +# passing `None`, overloads would have to be defined for every +# method that uses `ResponseT` which would lead to an unacceptable +# amount of code duplication and make it unreadable. See _base_client.py +# for example usage. +# +# This unfortunately means that you will either have +# to import this type and pass it explicitly: +# +# from scalar_api import NoneType +# client.get('/foo', cast_to=NoneType) +# +# or build it yourself: +# +# client.get('/foo', cast_to=type(None)) +if TYPE_CHECKING: + NoneType: Type[None] +else: + NoneType = type(None) + + +class RequestOptions(TypedDict, total=False): + headers: Headers + max_retries: int + timeout: float | Timeout | None + params: Query + extra_json: AnyMapping + idempotency_key: str + follow_redirects: bool + security: SecurityOptions + + +# Sentinel class used until PEP 0661 is accepted +class NotGiven: + """ + For parameters with a meaningful None value, we need to distinguish between + the user explicitly passing None, and the user not passing the parameter at + all. + + User code shouldn't need to use not_given directly. + + For example: + + ```py + def create(timeout: Timeout | None | NotGiven = not_given): ... + + + create(timeout=1) # 1s timeout + create(timeout=None) # No timeout + create() # Default timeout behavior + ``` + """ + + def __bool__(self) -> Literal[False]: + return False + + @override + def __repr__(self) -> str: + return "NOT_GIVEN" + + +not_given = NotGiven() +# for backwards compatibility: +NOT_GIVEN = NotGiven() + + +class Omit: + """ + To explicitly omit something from being sent in a request, use `omit`. + + ```py + # as the default `Content-Type` header is `application/json` that will be sent + client.post("/upload/files", files={"file": b"my raw file content"}) + + # you can't explicitly override the header as it has to be dynamically generated + # to look something like: 'multipart/form-data; boundary=0d8382fcf5f8c3be01ca2e11002d2983' + client.post(..., headers={"Content-Type": "multipart/form-data"}) + + # instead you can remove the default `application/json` header by passing omit + client.post(..., headers={"Content-Type": omit}) + ``` + """ + + def __bool__(self) -> Literal[False]: + return False + + +omit = Omit() + + +@runtime_checkable +class ModelBuilderProtocol(Protocol): + @classmethod + def build( + cls: type[_T], + *, + response: Response, + data: object, + ) -> _T: ... + + +Headers = Mapping[str, Union[str, Omit]] + + +class HeadersLikeProtocol(Protocol): + def get(self, __key: str) -> str | None: ... + + +HeadersLike = Union[Headers, HeadersLikeProtocol] + +ResponseT = TypeVar( + "ResponseT", + bound=Union[ + object, + str, + None, + "BaseModel", + List[Any], + Dict[str, Any], + Response, + ModelBuilderProtocol, + "APIResponse[Any]", + "AsyncAPIResponse[Any]", + ], +) + +StrBytesIntFloat = Union[str, bytes, int, float] + +# Note: copied from Pydantic +# https://github.com/pydantic/pydantic/blob/6f31f8f68ef011f84357330186f603ff295312fd/pydantic/main.py#L79 +IncEx: TypeAlias = Union[Set[int], Set[str], Mapping[int, Union["IncEx", bool]], Mapping[str, Union["IncEx", bool]]] + +PostParser = Callable[[Any], Any] + + +@runtime_checkable +class InheritsGeneric(Protocol): + """Represents a type that has inherited from `Generic` + + The `__orig_bases__` property can be used to determine the resolved + type variable for a given base class. + """ + + __orig_bases__: tuple[_GenericAlias] + + +class _GenericAlias(Protocol): + __origin__: type[object] + + +class HttpxSendArgs(TypedDict, total=False): + auth: httpx.Auth + follow_redirects: bool + + +_T_co = TypeVar("_T_co", covariant=True) + + +if TYPE_CHECKING: + # This works because str.__contains__ does not accept object (either in typeshed or at runtime) + # https://github.com/hauntsaninja/useful_types/blob/5e9710f3875107d068e7679fd7fec9cfab0eff3b/useful_types/__init__.py#L285 + # + # Note: index() and count() methods are intentionally omitted to allow pyright to properly + # infer TypedDict types when dict literals are used in lists assigned to SequenceNotStr. + class SequenceNotStr(Protocol[_T_co]): + @overload + def __getitem__(self, index: SupportsIndex, /) -> _T_co: ... + @overload + def __getitem__(self, index: slice, /) -> Sequence[_T_co]: ... + def __contains__(self, value: object, /) -> bool: ... + def __len__(self) -> int: ... + def __iter__(self) -> Iterator[_T_co]: ... + def __reversed__(self) -> Iterator[_T_co]: ... +else: + # just point this to a normal `Sequence` at runtime to avoid having to special case + # deserializing our custom sequence type + SequenceNotStr = Sequence diff --git a/src/_utils/__init__.py b/src/_utils/__init__.py new file mode 100644 index 0000000..1c090e5 --- /dev/null +++ b/src/_utils/__init__.py @@ -0,0 +1,64 @@ +from ._path import path_template as path_template +from ._sync import asyncify as asyncify +from ._proxy import LazyProxy as LazyProxy +from ._utils import ( + flatten as flatten, + is_dict as is_dict, + is_list as is_list, + is_given as is_given, + is_tuple as is_tuple, + json_safe as json_safe, + lru_cache as lru_cache, + is_mapping as is_mapping, + is_tuple_t as is_tuple_t, + is_iterable as is_iterable, + is_sequence as is_sequence, + coerce_float as coerce_float, + is_mapping_t as is_mapping_t, + removeprefix as removeprefix, + removesuffix as removesuffix, + extract_files as extract_files, + is_sequence_t as is_sequence_t, + required_args as required_args, + coerce_boolean as coerce_boolean, + coerce_integer as coerce_integer, + file_from_path as file_from_path, + strip_not_given as strip_not_given, + get_async_library as get_async_library, + maybe_coerce_float as maybe_coerce_float, + get_required_header as get_required_header, + maybe_coerce_boolean as maybe_coerce_boolean, + maybe_coerce_integer as maybe_coerce_integer, +) +from ._compat import ( + get_args as get_args, + is_union as is_union, + get_origin as get_origin, + is_typeddict as is_typeddict, + is_literal_type as is_literal_type, +) +from ._typing import ( + is_list_type as is_list_type, + is_union_type as is_union_type, + extract_type_arg as extract_type_arg, + is_iterable_type as is_iterable_type, + is_required_type as is_required_type, + is_sequence_type as is_sequence_type, + is_annotated_type as is_annotated_type, + is_type_alias_type as is_type_alias_type, + strip_annotated_type as strip_annotated_type, + extract_type_var_from_base as extract_type_var_from_base, +) +from ._streams import consume_sync_iterator as consume_sync_iterator, consume_async_iterator as consume_async_iterator +from ._transform import ( + PropertyInfo as PropertyInfo, + transform as transform, + async_transform as async_transform, + maybe_transform as maybe_transform, + async_maybe_transform as async_maybe_transform, +) +from ._reflection import ( + function_has_argument as function_has_argument, + assert_signatures_in_sync as assert_signatures_in_sync, +) +from ._datetime_parse import parse_date as parse_date, parse_datetime as parse_datetime diff --git a/src/_utils/_compat.py b/src/_utils/_compat.py new file mode 100644 index 0000000..2c70b29 --- /dev/null +++ b/src/_utils/_compat.py @@ -0,0 +1,45 @@ +from __future__ import annotations + +import sys +import typing_extensions +from typing import Any, Type, Union, Literal, Optional +from datetime import date, datetime +from typing_extensions import get_args as _get_args, get_origin as _get_origin + +from .._types import StrBytesIntFloat +from ._datetime_parse import parse_date as _parse_date, parse_datetime as _parse_datetime + +_LITERAL_TYPES = {Literal, typing_extensions.Literal} + + +def get_args(tp: type[Any]) -> tuple[Any, ...]: + return _get_args(tp) + + +def get_origin(tp: type[Any]) -> type[Any] | None: + return _get_origin(tp) + + +def is_union(tp: Optional[Type[Any]]) -> bool: + if sys.version_info < (3, 10): + return tp is Union # type: ignore[comparison-overlap] + else: + import types + + return tp is Union or tp is types.UnionType # type: ignore[comparison-overlap] + + +def is_typeddict(tp: Type[Any]) -> bool: + return typing_extensions.is_typeddict(tp) + + +def is_literal_type(tp: Type[Any]) -> bool: + return get_origin(tp) in _LITERAL_TYPES + + +def parse_date(value: Union[date, StrBytesIntFloat]) -> date: + return _parse_date(value) + + +def parse_datetime(value: Union[datetime, StrBytesIntFloat]) -> datetime: + return _parse_datetime(value) diff --git a/src/_utils/_datetime_parse.py b/src/_utils/_datetime_parse.py new file mode 100644 index 0000000..7cb9d9e --- /dev/null +++ b/src/_utils/_datetime_parse.py @@ -0,0 +1,136 @@ +""" +This file contains code from https://github.com/pydantic/pydantic/blob/main/pydantic/v1/datetime_parse.py +without the Pydantic v1 specific errors. +""" + +from __future__ import annotations + +import re +from typing import Dict, Union, Optional +from datetime import date, datetime, timezone, timedelta + +from .._types import StrBytesIntFloat + +date_expr = r"(?P\d{4})-(?P\d{1,2})-(?P\d{1,2})" +time_expr = ( + r"(?P\d{1,2}):(?P\d{1,2})" + r"(?::(?P\d{1,2})(?:\.(?P\d{1,6})\d{0,6})?)?" + r"(?PZ|[+-]\d{2}(?::?\d{2})?)?$" +) + +date_re = re.compile(f"{date_expr}$") +datetime_re = re.compile(f"{date_expr}[T ]{time_expr}") + + +EPOCH = datetime(1970, 1, 1) +# if greater than this, the number is in ms, if less than or equal it's in seconds +# (in seconds this is 11th October 2603, in ms it's 20th August 1970) +MS_WATERSHED = int(2e10) +# slightly more than datetime.max in ns - (datetime.max - EPOCH).total_seconds() * 1e9 +MAX_NUMBER = int(3e20) + + +def _get_numeric(value: StrBytesIntFloat, native_expected_type: str) -> Union[None, int, float]: + if isinstance(value, (int, float)): + return value + try: + return float(value) + except ValueError: + return None + except TypeError: + raise TypeError(f"invalid type; expected {native_expected_type}, string, bytes, int or float") from None + + +def _from_unix_seconds(seconds: Union[int, float]) -> datetime: + if seconds > MAX_NUMBER: + return datetime.max + elif seconds < -MAX_NUMBER: + return datetime.min + + while abs(seconds) > MS_WATERSHED: + seconds /= 1000 + dt = EPOCH + timedelta(seconds=seconds) + return dt.replace(tzinfo=timezone.utc) + + +def _parse_timezone(value: Optional[str]) -> Union[None, int, timezone]: + if value == "Z": + return timezone.utc + elif value is not None: + offset_mins = int(value[-2:]) if len(value) > 3 else 0 + offset = 60 * int(value[1:3]) + offset_mins + if value[0] == "-": + offset = -offset + return timezone(timedelta(minutes=offset)) + else: + return None + + +def parse_datetime(value: Union[datetime, StrBytesIntFloat]) -> datetime: + """ + Parse a datetime/int/float/string and return a datetime.datetime. + + This function supports time zone offsets. When the input contains one, + the output uses a timezone with a fixed offset from UTC. + + Raise ValueError if the input is well formatted but not a valid datetime. + Raise ValueError if the input isn't well formatted. + """ + if isinstance(value, datetime): + return value + + number = _get_numeric(value, "datetime") + if number is not None: + return _from_unix_seconds(number) + + if isinstance(value, bytes): + value = value.decode() + + assert not isinstance(value, (float, int)) + + match = datetime_re.match(value) + if match is None: + raise ValueError("invalid datetime format") + + kw = match.groupdict() + if kw["microsecond"]: + kw["microsecond"] = kw["microsecond"].ljust(6, "0") + + tzinfo = _parse_timezone(kw.pop("tzinfo")) + kw_: Dict[str, Union[None, int, timezone]] = {k: int(v) for k, v in kw.items() if v is not None} + kw_["tzinfo"] = tzinfo + + return datetime(**kw_) # type: ignore + + +def parse_date(value: Union[date, StrBytesIntFloat]) -> date: + """ + Parse a date/int/float/string and return a datetime.date. + + Raise ValueError if the input is well formatted but not a valid date. + Raise ValueError if the input isn't well formatted. + """ + if isinstance(value, date): + if isinstance(value, datetime): + return value.date() + else: + return value + + number = _get_numeric(value, "date") + if number is not None: + return _from_unix_seconds(number).date() + + if isinstance(value, bytes): + value = value.decode() + + assert not isinstance(value, (float, int)) + match = date_re.match(value) + if match is None: + raise ValueError("invalid date format") + + kw = {k: int(v) for k, v in match.groupdict().items()} + + try: + return date(**kw) + except ValueError: + raise ValueError("invalid date format") from None diff --git a/src/_utils/_json.py b/src/_utils/_json.py new file mode 100644 index 0000000..6058421 --- /dev/null +++ b/src/_utils/_json.py @@ -0,0 +1,35 @@ +import json +from typing import Any +from datetime import datetime +from typing_extensions import override + +import pydantic + +from .._compat import model_dump + + +def openapi_dumps(obj: Any) -> bytes: + """ + Serialize an object to UTF-8 encoded JSON bytes. + + Extends the standard json.dumps with support for additional types + commonly used in the SDK, such as `datetime`, `pydantic.BaseModel`, etc. + """ + return json.dumps( + obj, + cls=_CustomEncoder, + # Uses the same defaults as httpx's JSON serialization + ensure_ascii=False, + separators=(",", ":"), + allow_nan=False, + ).encode() + + +class _CustomEncoder(json.JSONEncoder): + @override + def default(self, o: Any) -> Any: + if isinstance(o, datetime): + return o.isoformat() + if isinstance(o, pydantic.BaseModel): + return model_dump(o, exclude_unset=True, mode="json", by_alias=True) + return super().default(o) diff --git a/src/_utils/_logs.py b/src/_utils/_logs.py new file mode 100644 index 0000000..bad6b59 --- /dev/null +++ b/src/_utils/_logs.py @@ -0,0 +1,25 @@ +import os +import logging + +logger: logging.Logger = logging.getLogger("scalar_api") +httpx_logger: logging.Logger = logging.getLogger("httpx") + + +def _basic_config() -> None: + # e.g. [2023-10-05 14:12:26 - scalar_api._base_client:818 - DEBUG] HTTP Request: POST http://127.0.0.1:4010/foo/bar "200 OK" + logging.basicConfig( + format="[%(asctime)s - %(name)s:%(lineno)d - %(levelname)s] %(message)s", + datefmt="%Y-%m-%d %H:%M:%S", + ) + + +def setup_logging() -> None: + env = os.environ.get("SCALAR_LOG") + if env == "debug": + _basic_config() + logger.setLevel(logging.DEBUG) + httpx_logger.setLevel(logging.DEBUG) + elif env == "info": + _basic_config() + logger.setLevel(logging.INFO) + httpx_logger.setLevel(logging.INFO) diff --git a/src/_utils/_path.py b/src/_utils/_path.py new file mode 100644 index 0000000..4d6e1e4 --- /dev/null +++ b/src/_utils/_path.py @@ -0,0 +1,127 @@ +from __future__ import annotations + +import re +from typing import ( + Any, + Mapping, + Callable, +) +from urllib.parse import quote + +# Matches '.' or '..' where each dot is either literal or percent-encoded (%2e / %2E). +_DOT_SEGMENT_RE = re.compile(r"^(?:\.|%2[eE]){1,2}$") + +_PLACEHOLDER_RE = re.compile(r"\{(\w+)\}") + + +def _quote_path_segment_part(value: str) -> str: + """Percent-encode `value` for use in a URI path segment. + + Considers characters not in `pchar` set from RFC 3986 §3.3 to be unsafe. + https://datatracker.ietf.org/doc/html/rfc3986#section-3.3 + """ + # quote() already treats unreserved characters (letters, digits, and -._~) + # as safe, so we only need to add sub-delims, ':', and '@'. + # Notably, unlike the default `safe` for quote(), / is unsafe and must be quoted. + return quote(value, safe="!$&'()*+,;=:@") + + +def _quote_query_part(value: str) -> str: + """Percent-encode `value` for use in a URI query string. + + Considers &, = and characters not in `query` set from RFC 3986 §3.4 to be unsafe. + https://datatracker.ietf.org/doc/html/rfc3986#section-3.4 + """ + return quote(value, safe="!$'()*+,;:@/?") + + +def _quote_fragment_part(value: str) -> str: + """Percent-encode `value` for use in a URI fragment. + + Considers characters not in `fragment` set from RFC 3986 §3.5 to be unsafe. + https://datatracker.ietf.org/doc/html/rfc3986#section-3.5 + """ + return quote(value, safe="!$&'()*+,;=:@/?") + + +def _interpolate( + template: str, + values: Mapping[str, Any], + quoter: Callable[[str], str], +) -> str: + """Replace {name} placeholders in `template`, quoting each value with `quoter`. + + Placeholder names are looked up in `values`. + + Raises: + KeyError: If a placeholder is not found in `values`. + """ + # re.split with a capturing group returns alternating + # [text, name, text, name, ..., text] elements. + parts = _PLACEHOLDER_RE.split(template) + + for i in range(1, len(parts), 2): + name = parts[i] + if name not in values: + raise KeyError(f"a value for placeholder {{{name}}} was not provided") + val = values[name] + if val is None: + parts[i] = "null" + elif isinstance(val, bool): + parts[i] = "true" if val else "false" + else: + parts[i] = quoter(str(values[name])) + + return "".join(parts) + + +def path_template(template: str, /, **kwargs: Any) -> str: + """Interpolate {name} placeholders in `template` from keyword arguments. + + Args: + template: The template string containing {name} placeholders. + **kwargs: Keyword arguments to interpolate into the template. + + Returns: + The template with placeholders interpolated and percent-encoded. + + Safe characters for percent-encoding are dependent on the URI component. + Placeholders in path and fragment portions are percent-encoded where the `segment` + and `fragment` sets from RFC 3986 respectively are considered safe. + Placeholders in the query portion are percent-encoded where the `query` set from + RFC 3986 §3.3 is considered safe except for = and & characters. + + Raises: + KeyError: If a placeholder is not found in `kwargs`. + ValueError: If resulting path contains /./ or /../ segments (including percent-encoded dot-segments). + """ + # Split the template into path, query, and fragment portions. + fragment_template: str | None = None + query_template: str | None = None + + rest = template + if "#" in rest: + rest, fragment_template = rest.split("#", 1) + if "?" in rest: + rest, query_template = rest.split("?", 1) + path_template = rest + + # Interpolate each portion with the appropriate quoting rules. + path_result = _interpolate(path_template, kwargs, _quote_path_segment_part) + + # Reject dot-segments (. and ..) in the final assembled path. The check + # runs after interpolation so that adjacent placeholders or a mix of static + # text and placeholders that together form a dot-segment are caught. + # Also reject percent-encoded dot-segments to protect against incorrectly + # implemented normalization in servers/proxies. + for segment in path_result.split("/"): + if _DOT_SEGMENT_RE.match(segment): + raise ValueError(f"Constructed path {path_result!r} contains dot-segment {segment!r} which is not allowed") + + result = path_result + if query_template is not None: + result += "?" + _interpolate(query_template, kwargs, _quote_query_part) + if fragment_template is not None: + result += "#" + _interpolate(fragment_template, kwargs, _quote_fragment_part) + + return result diff --git a/src/_utils/_proxy.py b/src/_utils/_proxy.py new file mode 100644 index 0000000..0f239a3 --- /dev/null +++ b/src/_utils/_proxy.py @@ -0,0 +1,65 @@ +from __future__ import annotations + +from abc import ABC, abstractmethod +from typing import Generic, TypeVar, Iterable, cast +from typing_extensions import override + +T = TypeVar("T") + + +class LazyProxy(Generic[T], ABC): + """Implements data methods to pretend that an instance is another instance. + + This includes forwarding attribute access and other methods. + """ + + # Note: we have to special case proxies that themselves return proxies + # to support using a proxy as a catch-all for any random access, e.g. `proxy.foo.bar.baz` + + def __getattr__(self, attr: str) -> object: + proxied = self.__get_proxied__() + if isinstance(proxied, LazyProxy): + return proxied # pyright: ignore + return getattr(proxied, attr) + + @override + def __repr__(self) -> str: + proxied = self.__get_proxied__() + if isinstance(proxied, LazyProxy): + return proxied.__class__.__name__ + return repr(self.__get_proxied__()) + + @override + def __str__(self) -> str: + proxied = self.__get_proxied__() + if isinstance(proxied, LazyProxy): + return proxied.__class__.__name__ + return str(proxied) + + @override + def __dir__(self) -> Iterable[str]: + proxied = self.__get_proxied__() + if isinstance(proxied, LazyProxy): + return [] + return proxied.__dir__() + + @property # type: ignore + @override + def __class__(self) -> type: # pyright: ignore + try: + proxied = self.__get_proxied__() + except Exception: + return type(self) + if issubclass(type(proxied), LazyProxy): + return type(proxied) + return proxied.__class__ + + def __get_proxied__(self) -> T: + return self.__load__() + + def __as_proxied__(self) -> T: + """Helper method that returns the current proxy, typed as the loaded object""" + return cast(T, self) + + @abstractmethod + def __load__(self) -> T: ... diff --git a/src/_utils/_reflection.py b/src/_utils/_reflection.py new file mode 100644 index 0000000..89aa712 --- /dev/null +++ b/src/_utils/_reflection.py @@ -0,0 +1,42 @@ +from __future__ import annotations + +import inspect +from typing import Any, Callable + + +def function_has_argument(func: Callable[..., Any], arg_name: str) -> bool: + """Returns whether or not the given function has a specific parameter""" + sig = inspect.signature(func) + return arg_name in sig.parameters + + +def assert_signatures_in_sync( + source_func: Callable[..., Any], + check_func: Callable[..., Any], + *, + exclude_params: set[str] = set(), +) -> None: + """Ensure that the signature of the second function matches the first.""" + + check_sig = inspect.signature(check_func) + source_sig = inspect.signature(source_func) + + errors: list[str] = [] + + for name, source_param in source_sig.parameters.items(): + if name in exclude_params: + continue + + custom_param = check_sig.parameters.get(name) + if not custom_param: + errors.append(f"the `{name}` param is missing") + continue + + if custom_param.annotation != source_param.annotation: + errors.append( + f"types for the `{name}` param are do not match; source={repr(source_param.annotation)} checking={repr(custom_param.annotation)}" + ) + continue + + if errors: + raise AssertionError(f"{len(errors)} errors encountered when comparing signatures:\n\n" + "\n\n".join(errors)) diff --git a/src/_utils/_resources_proxy.py b/src/_utils/_resources_proxy.py new file mode 100644 index 0000000..6d86fbe --- /dev/null +++ b/src/_utils/_resources_proxy.py @@ -0,0 +1,24 @@ +from __future__ import annotations + +from typing import Any +from typing_extensions import override + +from ._proxy import LazyProxy + + +class ResourcesProxy(LazyProxy[Any]): + """A proxy for the `scalar_api.resources` module. + + This is used so that we can lazily import `scalar_api.resources` only when + needed *and* so that users can just import `scalar_api` and reference `scalar_api.resources` + """ + + @override + def __load__(self) -> Any: + import importlib + + mod = importlib.import_module("scalar_api.resources") + return mod + + +resources = ResourcesProxy().__as_proxied__() diff --git a/src/_utils/_streams.py b/src/_utils/_streams.py new file mode 100644 index 0000000..f4a0208 --- /dev/null +++ b/src/_utils/_streams.py @@ -0,0 +1,12 @@ +from typing import Any +from typing_extensions import Iterator, AsyncIterator + + +def consume_sync_iterator(iterator: Iterator[Any]) -> None: + for _ in iterator: + ... + + +async def consume_async_iterator(iterator: AsyncIterator[Any]) -> None: + async for _ in iterator: + ... diff --git a/src/_utils/_sync.py b/src/_utils/_sync.py new file mode 100644 index 0000000..f6027c1 --- /dev/null +++ b/src/_utils/_sync.py @@ -0,0 +1,58 @@ +from __future__ import annotations + +import asyncio +import functools +from typing import TypeVar, Callable, Awaitable +from typing_extensions import ParamSpec + +import anyio +import sniffio +import anyio.to_thread + +T_Retval = TypeVar("T_Retval") +T_ParamSpec = ParamSpec("T_ParamSpec") + + +async def to_thread( + func: Callable[T_ParamSpec, T_Retval], /, *args: T_ParamSpec.args, **kwargs: T_ParamSpec.kwargs +) -> T_Retval: + if sniffio.current_async_library() == "asyncio": + return await asyncio.to_thread(func, *args, **kwargs) + + return await anyio.to_thread.run_sync( + functools.partial(func, *args, **kwargs), + ) + + +# inspired by `asyncer`, https://github.com/tiangolo/asyncer +def asyncify(function: Callable[T_ParamSpec, T_Retval]) -> Callable[T_ParamSpec, Awaitable[T_Retval]]: + """ + Take a blocking function and create an async one that receives the same + positional and keyword arguments. + + Usage: + + ```python + def blocking_func(arg1, arg2, kwarg1=None): + # blocking code + return result + + + result = asyncify(blocking_function)(arg1, arg2, kwarg1=value1) + ``` + + ## Arguments + + `function`: a blocking regular callable (e.g. a function) + + ## Return + + An async function that takes the same positional and keyword arguments as the + original one, that when called runs the same original function in a thread worker + and returns the result. + """ + + async def wrapper(*args: T_ParamSpec.args, **kwargs: T_ParamSpec.kwargs) -> T_Retval: + return await to_thread(function, *args, **kwargs) + + return wrapper diff --git a/src/_utils/_transform.py b/src/_utils/_transform.py new file mode 100644 index 0000000..5207549 --- /dev/null +++ b/src/_utils/_transform.py @@ -0,0 +1,457 @@ +from __future__ import annotations + +import io +import base64 +import pathlib +from typing import Any, Mapping, TypeVar, cast +from datetime import date, datetime +from typing_extensions import Literal, get_args, override, get_type_hints as _get_type_hints + +import anyio +import pydantic + +from ._utils import ( + is_list, + is_given, + lru_cache, + is_mapping, + is_iterable, + is_sequence, +) +from .._files import is_base64_file_input +from ._compat import get_origin, is_typeddict +from ._typing import ( + is_list_type, + is_union_type, + extract_type_arg, + is_iterable_type, + is_required_type, + is_sequence_type, + is_annotated_type, + strip_annotated_type, +) + +_T = TypeVar("_T") + + +# TODO: support for drilling globals() and locals() +# TODO: ensure works correctly with forward references in all cases + + +PropertyFormat = Literal["iso8601", "base64", "custom"] + + +class PropertyInfo: + """Metadata class to be used in Annotated types to provide information about a given type. + + For example: + + class MyParams(TypedDict): + account_holder_name: Annotated[str, PropertyInfo(alias='accountHolderName')] + + This means that {'account_holder_name': 'Robert'} will be transformed to {'accountHolderName': 'Robert'} before being sent to the API. + """ + + alias: str | None + format: PropertyFormat | None + format_template: str | None + discriminator: str | None + + def __init__( + self, + *, + alias: str | None = None, + format: PropertyFormat | None = None, + format_template: str | None = None, + discriminator: str | None = None, + ) -> None: + self.alias = alias + self.format = format + self.format_template = format_template + self.discriminator = discriminator + + @override + def __repr__(self) -> str: + return f"{self.__class__.__name__}(alias='{self.alias}', format={self.format}, format_template='{self.format_template}', discriminator='{self.discriminator}')" + + +def maybe_transform( + data: object, + expected_type: object, +) -> Any | None: + """Wrapper over `transform()` that allows `None` to be passed. + + See `transform()` for more details. + """ + if data is None: + return None + return transform(data, expected_type) + + +# Wrapper over _transform_recursive providing fake types +def transform( + data: _T, + expected_type: object, +) -> _T: + """Transform dictionaries based off of type information from the given type, for example: + + ```py + class Params(TypedDict, total=False): + card_id: Required[Annotated[str, PropertyInfo(alias="cardID")]] + + + transformed = transform({"card_id": ""}, Params) + # {'cardID': ''} + ``` + + Any keys / data that does not have type information given will be included as is. + + It should be noted that the transformations that this function does are not represented in the type system. + """ + transformed = _transform_recursive(data, annotation=cast(type, expected_type)) + return cast(_T, transformed) + + +@lru_cache(maxsize=8096) +def _get_annotated_type(type_: type) -> type | None: + """If the given type is an `Annotated` type then it is returned, if not `None` is returned. + + This also unwraps the type when applicable, e.g. `Required[Annotated[T, ...]]` + """ + if is_required_type(type_): + # Unwrap `Required[Annotated[T, ...]]` to `Annotated[T, ...]` + type_ = get_args(type_)[0] + + if is_annotated_type(type_): + return type_ + + return None + + +def _maybe_transform_key(key: str, type_: type) -> str: + """Transform the given `data` based on the annotations provided in `type_`. + + Note: this function only looks at `Annotated` types that contain `PropertyInfo` metadata. + """ + annotated_type = _get_annotated_type(type_) + if annotated_type is None: + # no `Annotated` definition for this type, no transformation needed + return key + + # ignore the first argument as it is the actual type + annotations = get_args(annotated_type)[1:] + for annotation in annotations: + if isinstance(annotation, PropertyInfo) and annotation.alias is not None: + return annotation.alias + + return key + + +def _no_transform_needed(annotation: type) -> bool: + return annotation == float or annotation == int + + +def _transform_recursive( + data: object, + *, + annotation: type, + inner_type: type | None = None, +) -> object: + """Transform the given data against the expected type. + + Args: + annotation: The direct type annotation given to the particular piece of data. + This may or may not be wrapped in metadata types, e.g. `Required[T]`, `Annotated[T, ...]` etc + + inner_type: If applicable, this is the "inside" type. This is useful in certain cases where the outside type + is a container type such as `List[T]`. In that case `inner_type` should be set to `T` so that each entry in + the list can be transformed using the metadata from the container type. + + Defaults to the same value as the `annotation` argument. + """ + from .._compat import model_dump + + if inner_type is None: + inner_type = annotation + + stripped_type = strip_annotated_type(inner_type) + origin = get_origin(stripped_type) or stripped_type + if is_typeddict(stripped_type) and is_mapping(data): + return _transform_typeddict(data, stripped_type) + + if origin == dict and is_mapping(data): + items_type = get_args(stripped_type)[1] + return {key: _transform_recursive(value, annotation=items_type) for key, value in data.items()} + + if ( + # List[T] + (is_list_type(stripped_type) and is_list(data)) + # Iterable[T] + or (is_iterable_type(stripped_type) and is_iterable(data) and not isinstance(data, str)) + # Sequence[T] + or (is_sequence_type(stripped_type) and is_sequence(data) and not isinstance(data, str)) + ): + # dicts are technically iterable, but it is an iterable on the keys of the dict and is not usually + # intended as an iterable, so we don't transform it. + if isinstance(data, dict): + return cast(object, data) + + inner_type = extract_type_arg(stripped_type, 0) + if _no_transform_needed(inner_type): + # for some types there is no need to transform anything, so we can get a small + # perf boost from skipping that work. + # + # but we still need to convert to a list to ensure the data is json-serializable + if is_list(data): + return data + return list(data) + + return [_transform_recursive(d, annotation=annotation, inner_type=inner_type) for d in data] + + if is_union_type(stripped_type): + # For union types we run the transformation against all subtypes to ensure that everything is transformed. + # + # TODO: there may be edge cases where the same normalized field name will transform to two different names + # in different subtypes. + for subtype in get_args(stripped_type): + data = _transform_recursive(data, annotation=annotation, inner_type=subtype) + return data + + if isinstance(data, pydantic.BaseModel): + return model_dump(data, exclude_unset=True, mode="json") + + annotated_type = _get_annotated_type(annotation) + if annotated_type is None: + return data + + # ignore the first argument as it is the actual type + annotations = get_args(annotated_type)[1:] + for annotation in annotations: + if isinstance(annotation, PropertyInfo) and annotation.format is not None: + return _format_data(data, annotation.format, annotation.format_template) + + return data + + +def _format_data(data: object, format_: PropertyFormat, format_template: str | None) -> object: + if isinstance(data, (date, datetime)): + if format_ == "iso8601": + return data.isoformat() + + if format_ == "custom" and format_template is not None: + return data.strftime(format_template) + + if format_ == "base64" and is_base64_file_input(data): + binary: str | bytes | None = None + + if isinstance(data, pathlib.Path): + binary = data.read_bytes() + elif isinstance(data, io.IOBase): + binary = data.read() + + if isinstance(binary, str): # type: ignore[unreachable] + binary = binary.encode() + + if not isinstance(binary, bytes): + raise RuntimeError(f"Could not read bytes from {data}; Received {type(binary)}") + + return base64.b64encode(binary).decode("ascii") + + return data + + +def _transform_typeddict( + data: Mapping[str, object], + expected_type: type, +) -> Mapping[str, object]: + result: dict[str, object] = {} + annotations = get_type_hints(expected_type, include_extras=True) + for key, value in data.items(): + if not is_given(value): + # we don't need to include omitted values here as they'll + # be stripped out before the request is sent anyway + continue + + type_ = annotations.get(key) + if type_ is None: + # we do not have a type annotation for this field, leave it as is + result[key] = value + else: + result[_maybe_transform_key(key, type_)] = _transform_recursive(value, annotation=type_) + return result + + +async def async_maybe_transform( + data: object, + expected_type: object, +) -> Any | None: + """Wrapper over `async_transform()` that allows `None` to be passed. + + See `async_transform()` for more details. + """ + if data is None: + return None + return await async_transform(data, expected_type) + + +async def async_transform( + data: _T, + expected_type: object, +) -> _T: + """Transform dictionaries based off of type information from the given type, for example: + + ```py + class Params(TypedDict, total=False): + card_id: Required[Annotated[str, PropertyInfo(alias="cardID")]] + + + transformed = transform({"card_id": ""}, Params) + # {'cardID': ''} + ``` + + Any keys / data that does not have type information given will be included as is. + + It should be noted that the transformations that this function does are not represented in the type system. + """ + transformed = await _async_transform_recursive(data, annotation=cast(type, expected_type)) + return cast(_T, transformed) + + +async def _async_transform_recursive( + data: object, + *, + annotation: type, + inner_type: type | None = None, +) -> object: + """Transform the given data against the expected type. + + Args: + annotation: The direct type annotation given to the particular piece of data. + This may or may not be wrapped in metadata types, e.g. `Required[T]`, `Annotated[T, ...]` etc + + inner_type: If applicable, this is the "inside" type. This is useful in certain cases where the outside type + is a container type such as `List[T]`. In that case `inner_type` should be set to `T` so that each entry in + the list can be transformed using the metadata from the container type. + + Defaults to the same value as the `annotation` argument. + """ + from .._compat import model_dump + + if inner_type is None: + inner_type = annotation + + stripped_type = strip_annotated_type(inner_type) + origin = get_origin(stripped_type) or stripped_type + if is_typeddict(stripped_type) and is_mapping(data): + return await _async_transform_typeddict(data, stripped_type) + + if origin == dict and is_mapping(data): + items_type = get_args(stripped_type)[1] + return {key: _transform_recursive(value, annotation=items_type) for key, value in data.items()} + + if ( + # List[T] + (is_list_type(stripped_type) and is_list(data)) + # Iterable[T] + or (is_iterable_type(stripped_type) and is_iterable(data) and not isinstance(data, str)) + # Sequence[T] + or (is_sequence_type(stripped_type) and is_sequence(data) and not isinstance(data, str)) + ): + # dicts are technically iterable, but it is an iterable on the keys of the dict and is not usually + # intended as an iterable, so we don't transform it. + if isinstance(data, dict): + return cast(object, data) + + inner_type = extract_type_arg(stripped_type, 0) + if _no_transform_needed(inner_type): + # for some types there is no need to transform anything, so we can get a small + # perf boost from skipping that work. + # + # but we still need to convert to a list to ensure the data is json-serializable + if is_list(data): + return data + return list(data) + + return [await _async_transform_recursive(d, annotation=annotation, inner_type=inner_type) for d in data] + + if is_union_type(stripped_type): + # For union types we run the transformation against all subtypes to ensure that everything is transformed. + # + # TODO: there may be edge cases where the same normalized field name will transform to two different names + # in different subtypes. + for subtype in get_args(stripped_type): + data = await _async_transform_recursive(data, annotation=annotation, inner_type=subtype) + return data + + if isinstance(data, pydantic.BaseModel): + return model_dump(data, exclude_unset=True, mode="json") + + annotated_type = _get_annotated_type(annotation) + if annotated_type is None: + return data + + # ignore the first argument as it is the actual type + annotations = get_args(annotated_type)[1:] + for annotation in annotations: + if isinstance(annotation, PropertyInfo) and annotation.format is not None: + return await _async_format_data(data, annotation.format, annotation.format_template) + + return data + + +async def _async_format_data(data: object, format_: PropertyFormat, format_template: str | None) -> object: + if isinstance(data, (date, datetime)): + if format_ == "iso8601": + return data.isoformat() + + if format_ == "custom" and format_template is not None: + return data.strftime(format_template) + + if format_ == "base64" and is_base64_file_input(data): + binary: str | bytes | None = None + + if isinstance(data, pathlib.Path): + binary = await anyio.Path(data).read_bytes() + elif isinstance(data, io.IOBase): + binary = data.read() + + if isinstance(binary, str): # type: ignore[unreachable] + binary = binary.encode() + + if not isinstance(binary, bytes): + raise RuntimeError(f"Could not read bytes from {data}; Received {type(binary)}") + + return base64.b64encode(binary).decode("ascii") + + return data + + +async def _async_transform_typeddict( + data: Mapping[str, object], + expected_type: type, +) -> Mapping[str, object]: + result: dict[str, object] = {} + annotations = get_type_hints(expected_type, include_extras=True) + for key, value in data.items(): + if not is_given(value): + # we don't need to include omitted values here as they'll + # be stripped out before the request is sent anyway + continue + + type_ = annotations.get(key) + if type_ is None: + # we do not have a type annotation for this field, leave it as is + result[key] = value + else: + result[_maybe_transform_key(key, type_)] = await _async_transform_recursive(value, annotation=type_) + return result + + +@lru_cache(maxsize=8096) +def get_type_hints( + obj: Any, + globalns: dict[str, Any] | None = None, + localns: Mapping[str, Any] | None = None, + include_extras: bool = False, +) -> dict[str, Any]: + return _get_type_hints(obj, globalns=globalns, localns=localns, include_extras=include_extras) diff --git a/src/_utils/_typing.py b/src/_utils/_typing.py new file mode 100644 index 0000000..193109f --- /dev/null +++ b/src/_utils/_typing.py @@ -0,0 +1,156 @@ +from __future__ import annotations + +import sys +import typing +import typing_extensions +from typing import Any, TypeVar, Iterable, cast +from collections import abc as _c_abc +from typing_extensions import ( + TypeIs, + Required, + Annotated, + get_args, + get_origin, +) + +from ._utils import lru_cache +from .._types import InheritsGeneric +from ._compat import is_union as _is_union + + +def is_annotated_type(typ: type) -> bool: + return get_origin(typ) == Annotated + + +def is_list_type(typ: type) -> bool: + return (get_origin(typ) or typ) == list + + +def is_sequence_type(typ: type) -> bool: + origin = get_origin(typ) or typ + return origin == typing_extensions.Sequence or origin == typing.Sequence or origin == _c_abc.Sequence + + +def is_iterable_type(typ: type) -> bool: + """If the given type is `typing.Iterable[T]`""" + origin = get_origin(typ) or typ + return origin == Iterable or origin == _c_abc.Iterable + + +def is_union_type(typ: type) -> bool: + return _is_union(get_origin(typ)) + + +def is_required_type(typ: type) -> bool: + return get_origin(typ) == Required + + +def is_typevar(typ: type) -> bool: + # type ignore is required because type checkers + # think this expression will always return False + return type(typ) == TypeVar # type: ignore + + +_TYPE_ALIAS_TYPES: tuple[type[typing_extensions.TypeAliasType], ...] = (typing_extensions.TypeAliasType,) +if sys.version_info >= (3, 12): + _TYPE_ALIAS_TYPES = (*_TYPE_ALIAS_TYPES, typing.TypeAliasType) + + +def is_type_alias_type(tp: Any, /) -> TypeIs[typing_extensions.TypeAliasType]: + """Return whether the provided argument is an instance of `TypeAliasType`. + + ```python + type Int = int + is_type_alias_type(Int) + # > True + Str = TypeAliasType("Str", str) + is_type_alias_type(Str) + # > True + ``` + """ + return isinstance(tp, _TYPE_ALIAS_TYPES) + + +# Extracts T from Annotated[T, ...] or from Required[Annotated[T, ...]] +@lru_cache(maxsize=8096) +def strip_annotated_type(typ: type) -> type: + if is_required_type(typ) or is_annotated_type(typ): + return strip_annotated_type(cast(type, get_args(typ)[0])) + + return typ + + +def extract_type_arg(typ: type, index: int) -> type: + args = get_args(typ) + try: + return cast(type, args[index]) + except IndexError as err: + raise RuntimeError(f"Expected type {typ} to have a type argument at index {index} but it did not") from err + + +def extract_type_var_from_base( + typ: type, + *, + generic_bases: tuple[type, ...], + index: int, + failure_message: str | None = None, +) -> type: + """Given a type like `Foo[T]`, returns the generic type variable `T`. + + This also handles the case where a concrete subclass is given, e.g. + ```py + class MyResponse(Foo[bytes]): + ... + + extract_type_var(MyResponse, bases=(Foo,), index=0) -> bytes + ``` + + And where a generic subclass is given: + ```py + _T = TypeVar('_T') + class MyResponse(Foo[_T]): + ... + + extract_type_var(MyResponse[bytes], bases=(Foo,), index=0) -> bytes + ``` + """ + cls = cast(object, get_origin(typ) or typ) + if cls in generic_bases: # pyright: ignore[reportUnnecessaryContains] + # we're given the class directly + return extract_type_arg(typ, index) + + # if a subclass is given + # --- + # this is needed as __orig_bases__ is not present in the typeshed stubs + # because it is intended to be for internal use only, however there does + # not seem to be a way to resolve generic TypeVars for inherited subclasses + # without using it. + if isinstance(cls, InheritsGeneric): + target_base_class: Any | None = None + for base in cls.__orig_bases__: + if base.__origin__ in generic_bases: + target_base_class = base + break + + if target_base_class is None: + raise RuntimeError( + "Could not find the generic base class;\n" + "This should never happen;\n" + f"Does {cls} inherit from one of {generic_bases} ?" + ) + + extracted = extract_type_arg(target_base_class, index) + if is_typevar(extracted): + # If the extracted type argument is itself a type variable + # then that means the subclass itself is generic, so we have + # to resolve the type argument from the class itself, not + # the base class. + # + # Note: if there is more than 1 type argument, the subclass could + # change the ordering of the type arguments, this is not currently + # supported. + return extract_type_arg(typ, index) + + return extracted + + raise RuntimeError(failure_message or f"Could not resolve inner type variable at index {index} for {typ}") diff --git a/src/_utils/_utils.py b/src/_utils/_utils.py new file mode 100644 index 0000000..8b051e2 --- /dev/null +++ b/src/_utils/_utils.py @@ -0,0 +1,433 @@ +from __future__ import annotations + +import os +import re +import inspect +import functools +from typing import ( + Any, + Tuple, + Mapping, + TypeVar, + Callable, + Iterable, + Sequence, + cast, + overload, +) +from pathlib import Path +from datetime import date, datetime +from typing_extensions import TypeGuard, get_args + +import sniffio + +from .._types import Omit, NotGiven, FileTypes, ArrayFormat, HeadersLike + +_T = TypeVar("_T") +_TupleT = TypeVar("_TupleT", bound=Tuple[object, ...]) +_MappingT = TypeVar("_MappingT", bound=Mapping[str, object]) +_SequenceT = TypeVar("_SequenceT", bound=Sequence[object]) +CallableT = TypeVar("CallableT", bound=Callable[..., Any]) + + +def flatten(t: Iterable[Iterable[_T]]) -> list[_T]: + return [item for sublist in t for item in sublist] + + +def extract_files( + # TODO: this needs to take Dict but variance issues..... + # create protocol type ? + query: Mapping[str, object], + *, + paths: Sequence[Sequence[str]], + array_format: ArrayFormat = "brackets", +) -> list[tuple[str, FileTypes]]: + """Recursively extract files from the given dictionary based on specified paths. + + A path may look like this ['foo', 'files', '', 'data']. + + ``array_format`` controls how ```` segments contribute to the emitted + field name. Supported values: ``"brackets"`` (``foo[]``), ``"repeat"`` and + ``"comma"`` (``foo``), ``"indices"`` (``foo[0]``, ``foo[1]``). + + Note: this mutates the given dictionary. + """ + files: list[tuple[str, FileTypes]] = [] + for path in paths: + files.extend(_extract_items(query, path, index=0, flattened_key=None, array_format=array_format)) + return files + + +def _array_suffix(array_format: ArrayFormat, array_index: int) -> str: + if array_format == "brackets": + return "[]" + if array_format == "indices": + return f"[{array_index}]" + if array_format == "repeat" or array_format == "comma": + # Both repeat the bare field name for each file part; there is no + # meaningful way to comma-join binary parts. + return "" + raise NotImplementedError( + f"Unknown array_format value: {array_format}, choose from {', '.join(get_args(ArrayFormat))}" + ) + + +def _extract_items( + obj: object, + path: Sequence[str], + *, + index: int, + flattened_key: str | None, + array_format: ArrayFormat, +) -> list[tuple[str, FileTypes]]: + try: + key = path[index] + except IndexError: + if not is_given(obj): + # no value was provided - we can safely ignore + return [] + + # cyclical import + from .._files import assert_is_file_content + + # We have exhausted the path, return the entry we found. + assert flattened_key is not None + + if is_list(obj): + files: list[tuple[str, FileTypes]] = [] + for array_index, entry in enumerate(obj): + suffix = _array_suffix(array_format, array_index) + emitted_key = (flattened_key + suffix) if flattened_key else suffix + assert_is_file_content(entry, key=emitted_key) + files.append((emitted_key, cast(FileTypes, entry))) + return files + + assert_is_file_content(obj, key=flattened_key) + return [(flattened_key, cast(FileTypes, obj))] + + index += 1 + if is_dict(obj): + try: + # Remove the field if there are no more dict keys in the path, + # only "" traversal markers or end. + if all(p == "" for p in path[index:]): + item = obj.pop(key) + else: + item = obj[key] + except KeyError: + # Key was not present in the dictionary, this is not indicative of an error + # as the given path may not point to a required field. We also do not want + # to enforce required fields as the API may differ from the spec in some cases. + return [] + if flattened_key is None: + flattened_key = key + else: + flattened_key += f"[{key}]" + return _extract_items( + item, + path, + index=index, + flattened_key=flattened_key, + array_format=array_format, + ) + elif is_list(obj): + if key != "": + return [] + + return flatten( + [ + _extract_items( + item, + path, + index=index, + flattened_key=( + (flattened_key if flattened_key is not None else "") + _array_suffix(array_format, array_index) + ), + array_format=array_format, + ) + for array_index, item in enumerate(obj) + ] + ) + + # Something unexpected was passed, just ignore it. + return [] + + +def is_given(obj: _T | NotGiven | Omit) -> TypeGuard[_T]: + return not isinstance(obj, NotGiven) and not isinstance(obj, Omit) + + +# Type safe methods for narrowing types with TypeVars. +# The default narrowing for isinstance(obj, dict) is dict[unknown, unknown], +# however this cause Pyright to rightfully report errors. As we know we don't +# care about the contained types we can safely use `object` in its place. +# +# There are two separate functions defined, `is_*` and `is_*_t` for different use cases. +# `is_*` is for when you're dealing with an unknown input +# `is_*_t` is for when you're narrowing a known union type to a specific subset + + +def is_tuple(obj: object) -> TypeGuard[tuple[object, ...]]: + return isinstance(obj, tuple) + + +def is_tuple_t(obj: _TupleT | object) -> TypeGuard[_TupleT]: + return isinstance(obj, tuple) + + +def is_sequence(obj: object) -> TypeGuard[Sequence[object]]: + return isinstance(obj, Sequence) + + +def is_sequence_t(obj: _SequenceT | object) -> TypeGuard[_SequenceT]: + return isinstance(obj, Sequence) + + +def is_mapping(obj: object) -> TypeGuard[Mapping[str, object]]: + return isinstance(obj, Mapping) + + +def is_mapping_t(obj: _MappingT | object) -> TypeGuard[_MappingT]: + return isinstance(obj, Mapping) + + +def is_dict(obj: object) -> TypeGuard[dict[object, object]]: + return isinstance(obj, dict) + + +def is_list(obj: object) -> TypeGuard[list[object]]: + return isinstance(obj, list) + + +def is_iterable(obj: object) -> TypeGuard[Iterable[object]]: + return isinstance(obj, Iterable) + + +# copied from https://github.com/Rapptz/RoboDanny +def human_join(seq: Sequence[str], *, delim: str = ", ", final: str = "or") -> str: + size = len(seq) + if size == 0: + return "" + + if size == 1: + return seq[0] + + if size == 2: + return f"{seq[0]} {final} {seq[1]}" + + return delim.join(seq[:-1]) + f" {final} {seq[-1]}" + + +def quote(string: str) -> str: + """Add single quotation marks around the given string. Does *not* do any escaping.""" + return f"'{string}'" + + +def required_args(*variants: Sequence[str]) -> Callable[[CallableT], CallableT]: + """Decorator to enforce a given set of arguments or variants of arguments are passed to the decorated function. + + Useful for enforcing runtime validation of overloaded functions. + + Example usage: + ```py + @overload + def foo(*, a: str) -> str: ... + + + @overload + def foo(*, b: bool) -> str: ... + + + # This enforces the same constraints that a static type checker would + # i.e. that either a or b must be passed to the function + @required_args(["a"], ["b"]) + def foo(*, a: str | None = None, b: bool | None = None) -> str: ... + ``` + """ + + def inner(func: CallableT) -> CallableT: + params = inspect.signature(func).parameters + positional = [ + name + for name, param in params.items() + if param.kind + in { + param.POSITIONAL_ONLY, + param.POSITIONAL_OR_KEYWORD, + } + ] + + @functools.wraps(func) + def wrapper(*args: object, **kwargs: object) -> object: + given_params: set[str] = set() + for i, _ in enumerate(args): + try: + given_params.add(positional[i]) + except IndexError: + raise TypeError( + f"{func.__name__}() takes {len(positional)} argument(s) but {len(args)} were given" + ) from None + + for key in kwargs.keys(): + given_params.add(key) + + for variant in variants: + matches = all((param in given_params for param in variant)) + if matches: + break + else: # no break + if len(variants) > 1: + variations = human_join( + ["(" + human_join([quote(arg) for arg in variant], final="and") + ")" for variant in variants] + ) + msg = f"Missing required arguments; Expected either {variations} arguments to be given" + else: + assert len(variants) > 0 + + # TODO: this error message is not deterministic + missing = list(set(variants[0]) - given_params) + if len(missing) > 1: + msg = f"Missing required arguments: {human_join([quote(arg) for arg in missing])}" + else: + msg = f"Missing required argument: {quote(missing[0])}" + raise TypeError(msg) + return func(*args, **kwargs) + + return wrapper # type: ignore + + return inner + + +_K = TypeVar("_K") +_V = TypeVar("_V") + + +@overload +def strip_not_given(obj: None) -> None: ... + + +@overload +def strip_not_given(obj: Mapping[_K, _V | NotGiven]) -> dict[_K, _V]: ... + + +@overload +def strip_not_given(obj: object) -> object: ... + + +def strip_not_given(obj: object | None) -> object: + """Remove all top-level keys where their values are instances of `NotGiven`""" + if obj is None: + return None + + if not is_mapping(obj): + return obj + + return {key: value for key, value in obj.items() if not isinstance(value, NotGiven)} + + +def coerce_integer(val: str) -> int: + return int(val, base=10) + + +def coerce_float(val: str) -> float: + return float(val) + + +def coerce_boolean(val: str) -> bool: + return val == "true" or val == "1" or val == "on" + + +def maybe_coerce_integer(val: str | None) -> int | None: + if val is None: + return None + return coerce_integer(val) + + +def maybe_coerce_float(val: str | None) -> float | None: + if val is None: + return None + return coerce_float(val) + + +def maybe_coerce_boolean(val: str | None) -> bool | None: + if val is None: + return None + return coerce_boolean(val) + + +def removeprefix(string: str, prefix: str) -> str: + """Remove a prefix from a string. + + Backport of `str.removeprefix` for Python < 3.9 + """ + if string.startswith(prefix): + return string[len(prefix) :] + return string + + +def removesuffix(string: str, suffix: str) -> str: + """Remove a suffix from a string. + + Backport of `str.removesuffix` for Python < 3.9 + """ + if string.endswith(suffix): + return string[: -len(suffix)] + return string + + +def file_from_path(path: str) -> FileTypes: + contents = Path(path).read_bytes() + file_name = os.path.basename(path) + return (file_name, contents) + + +def get_required_header(headers: HeadersLike, header: str) -> str: + lower_header = header.lower() + if is_mapping_t(headers): + # mypy doesn't understand the type narrowing here + for k, v in headers.items(): # type: ignore + if k.lower() == lower_header and isinstance(v, str): + return v + + # to deal with the case where the header looks like Scalar-Event-Id + intercaps_header = re.sub(r"([^\w])(\w)", lambda pat: pat.group(1) + pat.group(2).upper(), header.capitalize()) + + for normalized_header in [header, lower_header, header.upper(), intercaps_header]: + value = headers.get(normalized_header) + if value: + return value + + raise ValueError(f"Could not find {header} header") + + +def get_async_library() -> str: + try: + return sniffio.current_async_library() + except Exception: + return "false" + + +def lru_cache(*, maxsize: int | None = 128) -> Callable[[CallableT], CallableT]: + """A version of functools.lru_cache that retains the type signature + for the wrapped function arguments. + """ + wrapper = functools.lru_cache( # noqa: TID251 + maxsize=maxsize, + ) + return cast(Any, wrapper) # type: ignore[no-any-return] + + +def json_safe(data: object) -> object: + """Translates a mapping / sequence recursively in the same fashion + as `pydantic` v2's `model_dump(mode="json")`. + """ + if is_mapping(data): + return {json_safe(key): json_safe(value) for key, value in data.items()} + + if is_iterable(data) and not isinstance(data, (str, bytes, bytearray)): + return [json_safe(item) for item in data] + + if isinstance(data, (datetime, date)): + return data.isoformat() + + return data diff --git a/src/_version.py b/src/_version.py new file mode 100644 index 0000000..5e43458 --- /dev/null +++ b/src/_version.py @@ -0,0 +1,4 @@ +# File generated from our OpenAPI spec by Scalar. See README.md for details. + +__title__ = "scalarApi" +__version__ = "0.1.9" diff --git a/src/py.typed b/src/py.typed new file mode 100644 index 0000000..e69de29 diff --git a/src/resources/__init__.py b/src/resources/__init__.py new file mode 100644 index 0000000..e5d8992 --- /dev/null +++ b/src/resources/__init__.py @@ -0,0 +1,131 @@ +# File generated from our OpenAPI spec by Scalar. See README.md for details. + +from .registry import ( + RegistryResource, + AsyncRegistryResource, + RegistryResourceWithRawResponse, + AsyncRegistryResourceWithRawResponse, + RegistryResourceWithStreamingResponse, + AsyncRegistryResourceWithStreamingResponse, +) +from .schemas import ( + SchemasResource, + AsyncSchemasResource, + SchemasResourceWithRawResponse, + AsyncSchemasResourceWithRawResponse, + SchemasResourceWithStreamingResponse, + AsyncSchemasResourceWithStreamingResponse, +) +from .login_portals import ( + LoginPortalsResource, + AsyncLoginPortalsResource, + LoginPortalsResourceWithRawResponse, + AsyncLoginPortalsResourceWithRawResponse, + LoginPortalsResourceWithStreamingResponse, + AsyncLoginPortalsResourceWithStreamingResponse, +) +from .rules import ( + RulesResource, + AsyncRulesResource, + RulesResourceWithRawResponse, + AsyncRulesResourceWithRawResponse, + RulesResourceWithStreamingResponse, + AsyncRulesResourceWithStreamingResponse, +) +from .themes import ( + ThemesResource, + AsyncThemesResource, + ThemesResourceWithRawResponse, + AsyncThemesResourceWithRawResponse, + ThemesResourceWithStreamingResponse, + AsyncThemesResourceWithStreamingResponse, +) +from .teams import ( + TeamsResource, + AsyncTeamsResource, + TeamsResourceWithRawResponse, + AsyncTeamsResourceWithRawResponse, + TeamsResourceWithStreamingResponse, + AsyncTeamsResourceWithStreamingResponse, +) +from .scalar_docs import ( + ScalarDocsResource, + AsyncScalarDocsResource, + ScalarDocsResourceWithRawResponse, + AsyncScalarDocsResourceWithRawResponse, + ScalarDocsResourceWithStreamingResponse, + AsyncScalarDocsResourceWithStreamingResponse, +) +from .namespaces import ( + NamespacesResource, + AsyncNamespacesResource, + NamespacesResourceWithRawResponse, + AsyncNamespacesResourceWithRawResponse, + NamespacesResourceWithStreamingResponse, + AsyncNamespacesResourceWithStreamingResponse, +) +from .authentication import ( + AuthenticationResource, + AsyncAuthenticationResource, + AuthenticationResourceWithRawResponse, + AsyncAuthenticationResourceWithRawResponse, + AuthenticationResourceWithStreamingResponse, + AsyncAuthenticationResourceWithStreamingResponse, +) + +__all__ = [ + "RegistryResource", + "AsyncRegistryResource", + "RegistryResourceWithRawResponse", + "AsyncRegistryResourceWithRawResponse", + "RegistryResourceWithStreamingResponse", + "AsyncRegistryResourceWithStreamingResponse", + "SchemasResource", + "AsyncSchemasResource", + "SchemasResourceWithRawResponse", + "AsyncSchemasResourceWithRawResponse", + "SchemasResourceWithStreamingResponse", + "AsyncSchemasResourceWithStreamingResponse", + "LoginPortalsResource", + "AsyncLoginPortalsResource", + "LoginPortalsResourceWithRawResponse", + "AsyncLoginPortalsResourceWithRawResponse", + "LoginPortalsResourceWithStreamingResponse", + "AsyncLoginPortalsResourceWithStreamingResponse", + "RulesResource", + "AsyncRulesResource", + "RulesResourceWithRawResponse", + "AsyncRulesResourceWithRawResponse", + "RulesResourceWithStreamingResponse", + "AsyncRulesResourceWithStreamingResponse", + "ThemesResource", + "AsyncThemesResource", + "ThemesResourceWithRawResponse", + "AsyncThemesResourceWithRawResponse", + "ThemesResourceWithStreamingResponse", + "AsyncThemesResourceWithStreamingResponse", + "TeamsResource", + "AsyncTeamsResource", + "TeamsResourceWithRawResponse", + "AsyncTeamsResourceWithRawResponse", + "TeamsResourceWithStreamingResponse", + "AsyncTeamsResourceWithStreamingResponse", + "ScalarDocsResource", + "AsyncScalarDocsResource", + "ScalarDocsResourceWithRawResponse", + "AsyncScalarDocsResourceWithRawResponse", + "ScalarDocsResourceWithStreamingResponse", + "AsyncScalarDocsResourceWithStreamingResponse", + "NamespacesResource", + "AsyncNamespacesResource", + "NamespacesResourceWithRawResponse", + "AsyncNamespacesResourceWithRawResponse", + "NamespacesResourceWithStreamingResponse", + "AsyncNamespacesResourceWithStreamingResponse", + "AuthenticationResource", + "AsyncAuthenticationResource", + "AuthenticationResourceWithRawResponse", + "AsyncAuthenticationResourceWithRawResponse", + "AuthenticationResourceWithStreamingResponse", + "AsyncAuthenticationResourceWithStreamingResponse", +] diff --git a/src/resources/authentication.py b/src/resources/authentication.py new file mode 100644 index 0000000..37d5e9e --- /dev/null +++ b/src/resources/authentication.py @@ -0,0 +1,172 @@ +# File generated from our OpenAPI spec by Scalar. See README.md for details. + +from __future__ import annotations + +import httpx + +from .._types import Body, Omit, Query, Headers, NotGiven, omit, not_given +from .._utils import path_template, maybe_transform, async_maybe_transform +from .._compat import cached_property +from .._resource import SyncAPIResource, AsyncAPIResource +from .._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from .._base_client import make_request_options +from ..types.authentication_exchange_personal_token_response import AuthenticationExchangePersonalTokenResponse +from ..types import authentication_exchange_personal_token_params +from ..types.authentication_list_current_user_response import AuthenticationListCurrentUserResponse + +__all__ = ["AuthenticationResource", "AsyncAuthenticationResource"] + + +class AuthenticationResource(SyncAPIResource): + + @cached_property + def with_raw_response(self) -> AuthenticationResourceWithRawResponse: + return AuthenticationResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AuthenticationResourceWithStreamingResponse: + return AuthenticationResourceWithStreamingResponse(self) + + def exchange_personal_token( + self, + *, + personal_token: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + idempotency_key: str | None = None, + ) -> AuthenticationExchangePersonalTokenResponse: + """Exchange an API key for an access token.""" + return self._post( + "/v1/auth/exchange", + body=maybe_transform( + {"personal_token": personal_token}, + authentication_exchange_personal_token_params.AuthenticationExchangePersonalTokenParams, + ), + options=make_request_options(extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout, idempotency_key=idempotency_key), + cast_to=AuthenticationExchangePersonalTokenResponse, + ) + + def list_current_user( + self, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> AuthenticationListCurrentUserResponse: + """Get the authenticated user, including their available teams and theme.""" + return self._get( + "/v1/auth/me", + options=make_request_options(extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout), + cast_to=AuthenticationListCurrentUserResponse, + ) + + +class AsyncAuthenticationResource(AsyncAPIResource): + + @cached_property + def with_raw_response(self) -> AsyncAuthenticationResourceWithRawResponse: + return AsyncAuthenticationResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncAuthenticationResourceWithStreamingResponse: + return AsyncAuthenticationResourceWithStreamingResponse(self) + + async def exchange_personal_token( + self, + *, + personal_token: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + idempotency_key: str | None = None, + ) -> AuthenticationExchangePersonalTokenResponse: + """Exchange an API key for an access token.""" + return await self._post( + "/v1/auth/exchange", + body=await async_maybe_transform( + {"personal_token": personal_token}, + authentication_exchange_personal_token_params.AuthenticationExchangePersonalTokenParams, + ), + options=make_request_options(extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout, idempotency_key=idempotency_key), + cast_to=AuthenticationExchangePersonalTokenResponse, + ) + + async def list_current_user( + self, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> AuthenticationListCurrentUserResponse: + """Get the authenticated user, including their available teams and theme.""" + return await self._get( + "/v1/auth/me", + options=make_request_options(extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout), + cast_to=AuthenticationListCurrentUserResponse, + ) + + +class AuthenticationResourceWithRawResponse: + def __init__(self, authentication: AuthenticationResource) -> None: + self._authentication = authentication + + self.exchange_personal_token = to_raw_response_wrapper( + authentication.exchange_personal_token, + ) + self.list_current_user = to_raw_response_wrapper( + authentication.list_current_user, + ) + + +class AsyncAuthenticationResourceWithRawResponse: + def __init__(self, authentication: AsyncAuthenticationResource) -> None: + self._authentication = authentication + + self.exchange_personal_token = async_to_raw_response_wrapper( + authentication.exchange_personal_token, + ) + self.list_current_user = async_to_raw_response_wrapper( + authentication.list_current_user, + ) + + +class AuthenticationResourceWithStreamingResponse: + def __init__(self, authentication: AuthenticationResource) -> None: + self._authentication = authentication + + self.exchange_personal_token = to_streamed_response_wrapper( + authentication.exchange_personal_token, + ) + self.list_current_user = to_streamed_response_wrapper( + authentication.list_current_user, + ) + + +class AsyncAuthenticationResourceWithStreamingResponse: + def __init__(self, authentication: AsyncAuthenticationResource) -> None: + self._authentication = authentication + + self.exchange_personal_token = async_to_streamed_response_wrapper( + authentication.exchange_personal_token, + ) + self.list_current_user = async_to_streamed_response_wrapper( + authentication.list_current_user, + ) diff --git a/src/resources/login_portals.py b/src/resources/login_portals.py new file mode 100644 index 0000000..ff4d9bf --- /dev/null +++ b/src/resources/login_portals.py @@ -0,0 +1,362 @@ +# File generated from our OpenAPI spec by Scalar. See README.md for details. + +from __future__ import annotations + +import httpx + +from .._types import Body, Omit, Query, Headers, NotGiven, omit, not_given +from .._utils import path_template, maybe_transform, async_maybe_transform +from .._compat import cached_property +from .._resource import SyncAPIResource, AsyncAPIResource +from .._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from .._base_client import make_request_options +from ..types.login_portal_retrieve_response import LoginPortalRetrieveResponse +from ..types.login_portal_update_response import LoginPortalUpdateResponse +from ..types import login_portal_update_params +from ..types.login_portal_delete_response import LoginPortalDeleteResponse +from ..types.login_portal_create_response import LoginPortalCreateResponse +from ..types import login_portal_create_params +from ..types.login_portal_list_response import LoginPortalListResponse + +__all__ = ["LoginPortalsResource", "AsyncLoginPortalsResource"] + + +class LoginPortalsResource(SyncAPIResource): + + @cached_property + def with_raw_response(self) -> LoginPortalsResourceWithRawResponse: + return LoginPortalsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> LoginPortalsResourceWithStreamingResponse: + return LoginPortalsResourceWithStreamingResponse(self) + + def retrieve( + self, + slug: str, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> LoginPortalRetrieveResponse: + """Get a login portal by slug.""" + if not slug: + raise ValueError(f"Expected a non-empty value for `slug` but received {slug!r}") + return self._get( + path_template("/v1/login-portals/{slug}", **{"slug": slug}), + options=make_request_options(extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout), + cast_to=LoginPortalRetrieveResponse, + ) + + def update( + self, + slug: str, + *, + title: str | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + idempotency_key: str | None = None, + ) -> LoginPortalUpdateResponse: + """Update metadata for a login portal.""" + if not slug: + raise ValueError(f"Expected a non-empty value for `slug` but received {slug!r}") + return self._patch( + path_template("/v1/login-portals/{slug}", **{"slug": slug}), + body=maybe_transform( + {"title": title}, + login_portal_update_params.LoginPortalUpdateParams, + ), + options=make_request_options(extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout, idempotency_key=idempotency_key), + cast_to=LoginPortalUpdateResponse, + ) + + def delete( + self, + slug: str, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + idempotency_key: str | None = None, + ) -> LoginPortalDeleteResponse: + """Delete a login portal.""" + if not slug: + raise ValueError(f"Expected a non-empty value for `slug` but received {slug!r}") + return self._delete( + path_template("/v1/login-portals/{slug}", **{"slug": slug}), + options=make_request_options(extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout, idempotency_key=idempotency_key), + cast_to=LoginPortalDeleteResponse, + ) + + def create( + self, + *, + title: str, + slug: str, + email: object, + page: object, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + idempotency_key: str | None = None, + ) -> LoginPortalCreateResponse: + """Create a login portal for the current team.""" + return self._post( + "/v1/login-portals", + body=maybe_transform( + { + "title": title, + "slug": slug, + "email": email, + "page": page, + }, + login_portal_create_params.LoginPortalCreateParams, + ), + options=make_request_options(extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout, idempotency_key=idempotency_key), + cast_to=LoginPortalCreateResponse, + ) + + def list( + self, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> LoginPortalListResponse: + """List all login portals for the current team.""" + return self._get( + "/v1/login-portals", + options=make_request_options(extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout), + cast_to=LoginPortalListResponse, + ) + + +class AsyncLoginPortalsResource(AsyncAPIResource): + + @cached_property + def with_raw_response(self) -> AsyncLoginPortalsResourceWithRawResponse: + return AsyncLoginPortalsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncLoginPortalsResourceWithStreamingResponse: + return AsyncLoginPortalsResourceWithStreamingResponse(self) + + async def retrieve( + self, + slug: str, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> LoginPortalRetrieveResponse: + """Get a login portal by slug.""" + if not slug: + raise ValueError(f"Expected a non-empty value for `slug` but received {slug!r}") + return await self._get( + path_template("/v1/login-portals/{slug}", **{"slug": slug}), + options=make_request_options(extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout), + cast_to=LoginPortalRetrieveResponse, + ) + + async def update( + self, + slug: str, + *, + title: str | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + idempotency_key: str | None = None, + ) -> LoginPortalUpdateResponse: + """Update metadata for a login portal.""" + if not slug: + raise ValueError(f"Expected a non-empty value for `slug` but received {slug!r}") + return await self._patch( + path_template("/v1/login-portals/{slug}", **{"slug": slug}), + body=await async_maybe_transform( + {"title": title}, + login_portal_update_params.LoginPortalUpdateParams, + ), + options=make_request_options(extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout, idempotency_key=idempotency_key), + cast_to=LoginPortalUpdateResponse, + ) + + async def delete( + self, + slug: str, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + idempotency_key: str | None = None, + ) -> LoginPortalDeleteResponse: + """Delete a login portal.""" + if not slug: + raise ValueError(f"Expected a non-empty value for `slug` but received {slug!r}") + return await self._delete( + path_template("/v1/login-portals/{slug}", **{"slug": slug}), + options=make_request_options(extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout, idempotency_key=idempotency_key), + cast_to=LoginPortalDeleteResponse, + ) + + async def create( + self, + *, + title: str, + slug: str, + email: object, + page: object, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + idempotency_key: str | None = None, + ) -> LoginPortalCreateResponse: + """Create a login portal for the current team.""" + return await self._post( + "/v1/login-portals", + body=await async_maybe_transform( + { + "title": title, + "slug": slug, + "email": email, + "page": page, + }, + login_portal_create_params.LoginPortalCreateParams, + ), + options=make_request_options(extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout, idempotency_key=idempotency_key), + cast_to=LoginPortalCreateResponse, + ) + + async def list( + self, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> LoginPortalListResponse: + """List all login portals for the current team.""" + return await self._get( + "/v1/login-portals", + options=make_request_options(extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout), + cast_to=LoginPortalListResponse, + ) + + +class LoginPortalsResourceWithRawResponse: + def __init__(self, login_portals: LoginPortalsResource) -> None: + self._login_portals = login_portals + + self.retrieve = to_raw_response_wrapper( + login_portals.retrieve, + ) + self.update = to_raw_response_wrapper( + login_portals.update, + ) + self.delete = to_raw_response_wrapper( + login_portals.delete, + ) + self.create = to_raw_response_wrapper( + login_portals.create, + ) + self.list = to_raw_response_wrapper( + login_portals.list, + ) + + +class AsyncLoginPortalsResourceWithRawResponse: + def __init__(self, login_portals: AsyncLoginPortalsResource) -> None: + self._login_portals = login_portals + + self.retrieve = async_to_raw_response_wrapper( + login_portals.retrieve, + ) + self.update = async_to_raw_response_wrapper( + login_portals.update, + ) + self.delete = async_to_raw_response_wrapper( + login_portals.delete, + ) + self.create = async_to_raw_response_wrapper( + login_portals.create, + ) + self.list = async_to_raw_response_wrapper( + login_portals.list, + ) + + +class LoginPortalsResourceWithStreamingResponse: + def __init__(self, login_portals: LoginPortalsResource) -> None: + self._login_portals = login_portals + + self.retrieve = to_streamed_response_wrapper( + login_portals.retrieve, + ) + self.update = to_streamed_response_wrapper( + login_portals.update, + ) + self.delete = to_streamed_response_wrapper( + login_portals.delete, + ) + self.create = to_streamed_response_wrapper( + login_portals.create, + ) + self.list = to_streamed_response_wrapper( + login_portals.list, + ) + + +class AsyncLoginPortalsResourceWithStreamingResponse: + def __init__(self, login_portals: AsyncLoginPortalsResource) -> None: + self._login_portals = login_portals + + self.retrieve = async_to_streamed_response_wrapper( + login_portals.retrieve, + ) + self.update = async_to_streamed_response_wrapper( + login_portals.update, + ) + self.delete = async_to_streamed_response_wrapper( + login_portals.delete, + ) + self.create = async_to_streamed_response_wrapper( + login_portals.create, + ) + self.list = async_to_streamed_response_wrapper( + login_portals.list, + ) diff --git a/src/resources/namespaces.py b/src/resources/namespaces.py new file mode 100644 index 0000000..52f6303 --- /dev/null +++ b/src/resources/namespaces.py @@ -0,0 +1,112 @@ +# File generated from our OpenAPI spec by Scalar. See README.md for details. + +from __future__ import annotations + +import httpx + +from .._types import Body, Omit, Query, Headers, NotGiven, omit, not_given +from .._utils import path_template, maybe_transform, async_maybe_transform +from .._compat import cached_property +from .._resource import SyncAPIResource, AsyncAPIResource +from .._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from .._base_client import make_request_options +from ..types.namespace_list_response import NamespaceListResponse + +__all__ = ["NamespacesResource", "AsyncNamespacesResource"] + + +class NamespacesResource(SyncAPIResource): + + @cached_property + def with_raw_response(self) -> NamespacesResourceWithRawResponse: + return NamespacesResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> NamespacesResourceWithStreamingResponse: + return NamespacesResourceWithStreamingResponse(self) + + def list( + self, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> NamespaceListResponse: + """Get all namespaces for the current team""" + return self._get( + "/v1/namespaces", + options=make_request_options(extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout), + cast_to=NamespaceListResponse, + ) + + +class AsyncNamespacesResource(AsyncAPIResource): + + @cached_property + def with_raw_response(self) -> AsyncNamespacesResourceWithRawResponse: + return AsyncNamespacesResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncNamespacesResourceWithStreamingResponse: + return AsyncNamespacesResourceWithStreamingResponse(self) + + async def list( + self, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> NamespaceListResponse: + """Get all namespaces for the current team""" + return await self._get( + "/v1/namespaces", + options=make_request_options(extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout), + cast_to=NamespaceListResponse, + ) + + +class NamespacesResourceWithRawResponse: + def __init__(self, namespaces: NamespacesResource) -> None: + self._namespaces = namespaces + + self.list = to_raw_response_wrapper( + namespaces.list, + ) + + +class AsyncNamespacesResourceWithRawResponse: + def __init__(self, namespaces: AsyncNamespacesResource) -> None: + self._namespaces = namespaces + + self.list = async_to_raw_response_wrapper( + namespaces.list, + ) + + +class NamespacesResourceWithStreamingResponse: + def __init__(self, namespaces: NamespacesResource) -> None: + self._namespaces = namespaces + + self.list = to_streamed_response_wrapper( + namespaces.list, + ) + + +class AsyncNamespacesResourceWithStreamingResponse: + def __init__(self, namespaces: AsyncNamespacesResource) -> None: + self._namespaces = namespaces + + self.list = async_to_streamed_response_wrapper( + namespaces.list, + ) diff --git a/src/resources/registry.py b/src/resources/registry.py new file mode 100644 index 0000000..be45f27 --- /dev/null +++ b/src/resources/registry.py @@ -0,0 +1,923 @@ +# File generated from our OpenAPI spec by Scalar. See README.md for details. + +from __future__ import annotations + +import httpx + +from .._types import Body, Omit, Query, Headers, NotGiven, omit, not_given +from .._utils import path_template, maybe_transform, async_maybe_transform +from .._compat import cached_property +from .._resource import SyncAPIResource, AsyncAPIResource +from .._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from .._base_client import make_request_options +from ..types.registry_list_all_api_documents_response import RegistryListAllApiDocumentsResponse +from ..types.registry_list_api_documents_response import RegistryListApiDocumentsResponse +from ..types.registry_create_api_document_response import RegistryCreateApiDocumentResponse +from ..types import registry_create_api_document_params +from ..types.registry_update_api_document_response import RegistryUpdateApiDocumentResponse +from ..types import registry_update_api_document_params +from ..types.registry_delete_api_document_response import RegistryDeleteApiDocumentResponse +from ..types.registry_retrieve_api_document_version_response import RegistryRetrieveApiDocumentVersionResponse +from ..types.registry_update_api_document_version_response import RegistryUpdateApiDocumentVersionResponse +from ..types import registry_update_api_document_version_params +from ..types.registry_delete_api_document_version_response import RegistryDeleteApiDocumentVersionResponse +from ..types.registry_list_api_document_version_metadata_response import RegistryListApiDocumentVersionMetadataResponse +from ..types.registry_create_api_document_version_response import RegistryCreateApiDocumentVersionResponse +from ..types import registry_create_api_document_version_params +from ..types.registry_create_api_document_access_group_response import RegistryCreateApiDocumentAccessGroupResponse +from ..types import registry_create_api_document_access_group_params +from ..types.registry_delete_api_document_access_group_response import RegistryDeleteApiDocumentAccessGroupResponse +from ..types import registry_delete_api_document_access_group_params + +__all__ = ["RegistryResource", "AsyncRegistryResource"] + + +class RegistryResource(SyncAPIResource): + + @cached_property + def with_raw_response(self) -> RegistryResourceWithRawResponse: + return RegistryResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> RegistryResourceWithStreamingResponse: + return RegistryResourceWithStreamingResponse(self) + + def list_all_api_documents( + self, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> RegistryListAllApiDocumentsResponse: + """List all API documents across every namespace the caller can access.""" + return self._get( + "/v1/apis", + options=make_request_options(extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout), + cast_to=RegistryListAllApiDocumentsResponse, + ) + + def list_api_documents( + self, + namespace: str, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> RegistryListApiDocumentsResponse: + """List API documents in a namespace.""" + if not namespace: + raise ValueError(f"Expected a non-empty value for `namespace` but received {namespace!r}") + return self._get( + path_template("/v1/apis/{namespace}", **{"namespace": namespace}), + options=make_request_options(extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout), + cast_to=RegistryListApiDocumentsResponse, + ) + + def create_api_document( + self, + namespace: str, + *, + title: str, + description: str | Omit = omit, + version: str, + slug: str, + ruleset: str | Omit = omit, + is_private: bool | Omit = omit, + document: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + idempotency_key: str | None = None, + ) -> RegistryCreateApiDocumentResponse: + """Create an API document.""" + if not namespace: + raise ValueError(f"Expected a non-empty value for `namespace` but received {namespace!r}") + return self._post( + path_template("/v1/apis/{namespace}", **{"namespace": namespace}), + body=maybe_transform( + { + "title": title, + "description": description, + "version": version, + "slug": slug, + "ruleset": ruleset, + "is_private": is_private, + "document": document, + }, + registry_create_api_document_params.RegistryCreateApiDocumentParams, + ), + options=make_request_options(extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout, idempotency_key=idempotency_key), + cast_to=RegistryCreateApiDocumentResponse, + ) + + def update_api_document( + self, + slug: str, + *, + namespace: str, + title: str | Omit = omit, + description: str | Omit = omit, + is_private: bool | Omit = omit, + ruleset: str | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + idempotency_key: str | None = None, + ) -> RegistryUpdateApiDocumentResponse: + """Update metadata for an API document.""" + if not namespace: + raise ValueError(f"Expected a non-empty value for `namespace` but received {namespace!r}") + if not slug: + raise ValueError(f"Expected a non-empty value for `slug` but received {slug!r}") + return self._patch( + path_template("/v1/apis/{namespace}/{slug}", **{"namespace": namespace, "slug": slug}), + body=maybe_transform( + { + "title": title, + "description": description, + "is_private": is_private, + "ruleset": ruleset, + }, + registry_update_api_document_params.RegistryUpdateApiDocumentParams, + ), + options=make_request_options(extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout, idempotency_key=idempotency_key), + cast_to=RegistryUpdateApiDocumentResponse, + ) + + def delete_api_document( + self, + slug: str, + *, + namespace: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + idempotency_key: str | None = None, + ) -> RegistryDeleteApiDocumentResponse: + """Delete an API document and all versions.""" + if not namespace: + raise ValueError(f"Expected a non-empty value for `namespace` but received {namespace!r}") + if not slug: + raise ValueError(f"Expected a non-empty value for `slug` but received {slug!r}") + return self._delete( + path_template("/v1/apis/{namespace}/{slug}", **{"namespace": namespace, "slug": slug}), + options=make_request_options(extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout, idempotency_key=idempotency_key), + cast_to=RegistryDeleteApiDocumentResponse, + ) + + def retrieve_api_document_version( + self, + semver: str, + *, + namespace: str, + slug: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> RegistryRetrieveApiDocumentVersionResponse: + """Get a specific API document version.""" + if not namespace: + raise ValueError(f"Expected a non-empty value for `namespace` but received {namespace!r}") + if not slug: + raise ValueError(f"Expected a non-empty value for `slug` but received {slug!r}") + if not semver: + raise ValueError(f"Expected a non-empty value for `semver` but received {semver!r}") + return self._get( + path_template("/v1/apis/{namespace}/{slug}/version/{semver}", **{"namespace": namespace, "slug": slug, "semver": semver}), + options=make_request_options(extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout), + cast_to=RegistryRetrieveApiDocumentVersionResponse, + ) + + def update_api_document_version( + self, + semver: str, + *, + namespace: str, + slug: str, + document: str, + last_known_version_sha: str | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + idempotency_key: str | None = None, + ) -> RegistryUpdateApiDocumentVersionResponse: + """Update the registry file content for an API document version.""" + if not namespace: + raise ValueError(f"Expected a non-empty value for `namespace` but received {namespace!r}") + if not slug: + raise ValueError(f"Expected a non-empty value for `slug` but received {slug!r}") + if not semver: + raise ValueError(f"Expected a non-empty value for `semver` but received {semver!r}") + return self._patch( + path_template("/v1/apis/{namespace}/{slug}/version/{semver}", **{"namespace": namespace, "slug": slug, "semver": semver}), + body=maybe_transform( + { + "document": document, + "last_known_version_sha": last_known_version_sha, + }, + registry_update_api_document_version_params.RegistryUpdateApiDocumentVersionParams, + ), + options=make_request_options(extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout, idempotency_key=idempotency_key), + cast_to=RegistryUpdateApiDocumentVersionResponse, + ) + + def delete_api_document_version( + self, + semver: str, + *, + namespace: str, + slug: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + idempotency_key: str | None = None, + ) -> RegistryDeleteApiDocumentVersionResponse: + """Delete a specific API document version.""" + if not namespace: + raise ValueError(f"Expected a non-empty value for `namespace` but received {namespace!r}") + if not slug: + raise ValueError(f"Expected a non-empty value for `slug` but received {slug!r}") + if not semver: + raise ValueError(f"Expected a non-empty value for `semver` but received {semver!r}") + return self._delete( + path_template("/v1/apis/{namespace}/{slug}/version/{semver}", **{"namespace": namespace, "slug": slug, "semver": semver}), + options=make_request_options(extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout, idempotency_key=idempotency_key), + cast_to=RegistryDeleteApiDocumentVersionResponse, + ) + + def list_api_document_version_metadata( + self, + semver: str, + *, + namespace: str, + slug: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> RegistryListApiDocumentVersionMetadataResponse: + """Get metadata (uid, content shas, version sha, tags) for a specific API document version.""" + if not namespace: + raise ValueError(f"Expected a non-empty value for `namespace` but received {namespace!r}") + if not slug: + raise ValueError(f"Expected a non-empty value for `slug` but received {slug!r}") + if not semver: + raise ValueError(f"Expected a non-empty value for `semver` but received {semver!r}") + return self._get( + path_template("/v1/apis/{namespace}/{slug}/version/{semver}/metadata", **{"namespace": namespace, "slug": slug, "semver": semver}), + options=make_request_options(extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout), + cast_to=RegistryListApiDocumentVersionMetadataResponse, + ) + + def create_api_document_version( + self, + slug: str, + *, + namespace: str, + version: str, + document: str, + force: bool | Omit = omit, + last_known_version_sha: str | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + idempotency_key: str | None = None, + ) -> RegistryCreateApiDocumentVersionResponse: + """Create a new API document version.""" + if not namespace: + raise ValueError(f"Expected a non-empty value for `namespace` but received {namespace!r}") + if not slug: + raise ValueError(f"Expected a non-empty value for `slug` but received {slug!r}") + return self._post( + path_template("/v1/apis/{namespace}/{slug}/version", **{"namespace": namespace, "slug": slug}), + body=maybe_transform( + { + "version": version, + "document": document, + "force": force, + "last_known_version_sha": last_known_version_sha, + }, + registry_create_api_document_version_params.RegistryCreateApiDocumentVersionParams, + ), + options=make_request_options(extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout, idempotency_key=idempotency_key), + cast_to=RegistryCreateApiDocumentVersionResponse, + ) + + def create_api_document_access_group( + self, + slug: str, + *, + namespace: str, + access_group_slug: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + idempotency_key: str | None = None, + ) -> RegistryCreateApiDocumentAccessGroupResponse: + """Add an access group to an API document.""" + if not namespace: + raise ValueError(f"Expected a non-empty value for `namespace` but received {namespace!r}") + if not slug: + raise ValueError(f"Expected a non-empty value for `slug` but received {slug!r}") + return self._post( + path_template("/v1/apis/{namespace}/{slug}/access-group", **{"namespace": namespace, "slug": slug}), + body=maybe_transform( + {"access_group_slug": access_group_slug}, + registry_create_api_document_access_group_params.RegistryCreateApiDocumentAccessGroupParams, + ), + options=make_request_options(extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout, idempotency_key=idempotency_key), + cast_to=RegistryCreateApiDocumentAccessGroupResponse, + ) + + def delete_api_document_access_group( + self, + slug: str, + *, + namespace: str, + access_group_slug: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + idempotency_key: str | None = None, + ) -> RegistryDeleteApiDocumentAccessGroupResponse: + """Remove an access group from an API document.""" + if not namespace: + raise ValueError(f"Expected a non-empty value for `namespace` but received {namespace!r}") + if not slug: + raise ValueError(f"Expected a non-empty value for `slug` but received {slug!r}") + return self._delete( + path_template("/v1/apis/{namespace}/{slug}/access-group", **{"namespace": namespace, "slug": slug}), + body=maybe_transform( + {"access_group_slug": access_group_slug}, + registry_delete_api_document_access_group_params.RegistryDeleteApiDocumentAccessGroupParams, + ), + options=make_request_options(extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout, idempotency_key=idempotency_key), + cast_to=RegistryDeleteApiDocumentAccessGroupResponse, + ) + + +class AsyncRegistryResource(AsyncAPIResource): + + @cached_property + def with_raw_response(self) -> AsyncRegistryResourceWithRawResponse: + return AsyncRegistryResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncRegistryResourceWithStreamingResponse: + return AsyncRegistryResourceWithStreamingResponse(self) + + async def list_all_api_documents( + self, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> RegistryListAllApiDocumentsResponse: + """List all API documents across every namespace the caller can access.""" + return await self._get( + "/v1/apis", + options=make_request_options(extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout), + cast_to=RegistryListAllApiDocumentsResponse, + ) + + async def list_api_documents( + self, + namespace: str, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> RegistryListApiDocumentsResponse: + """List API documents in a namespace.""" + if not namespace: + raise ValueError(f"Expected a non-empty value for `namespace` but received {namespace!r}") + return await self._get( + path_template("/v1/apis/{namespace}", **{"namespace": namespace}), + options=make_request_options(extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout), + cast_to=RegistryListApiDocumentsResponse, + ) + + async def create_api_document( + self, + namespace: str, + *, + title: str, + description: str | Omit = omit, + version: str, + slug: str, + ruleset: str | Omit = omit, + is_private: bool | Omit = omit, + document: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + idempotency_key: str | None = None, + ) -> RegistryCreateApiDocumentResponse: + """Create an API document.""" + if not namespace: + raise ValueError(f"Expected a non-empty value for `namespace` but received {namespace!r}") + return await self._post( + path_template("/v1/apis/{namespace}", **{"namespace": namespace}), + body=await async_maybe_transform( + { + "title": title, + "description": description, + "version": version, + "slug": slug, + "ruleset": ruleset, + "is_private": is_private, + "document": document, + }, + registry_create_api_document_params.RegistryCreateApiDocumentParams, + ), + options=make_request_options(extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout, idempotency_key=idempotency_key), + cast_to=RegistryCreateApiDocumentResponse, + ) + + async def update_api_document( + self, + slug: str, + *, + namespace: str, + title: str | Omit = omit, + description: str | Omit = omit, + is_private: bool | Omit = omit, + ruleset: str | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + idempotency_key: str | None = None, + ) -> RegistryUpdateApiDocumentResponse: + """Update metadata for an API document.""" + if not namespace: + raise ValueError(f"Expected a non-empty value for `namespace` but received {namespace!r}") + if not slug: + raise ValueError(f"Expected a non-empty value for `slug` but received {slug!r}") + return await self._patch( + path_template("/v1/apis/{namespace}/{slug}", **{"namespace": namespace, "slug": slug}), + body=await async_maybe_transform( + { + "title": title, + "description": description, + "is_private": is_private, + "ruleset": ruleset, + }, + registry_update_api_document_params.RegistryUpdateApiDocumentParams, + ), + options=make_request_options(extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout, idempotency_key=idempotency_key), + cast_to=RegistryUpdateApiDocumentResponse, + ) + + async def delete_api_document( + self, + slug: str, + *, + namespace: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + idempotency_key: str | None = None, + ) -> RegistryDeleteApiDocumentResponse: + """Delete an API document and all versions.""" + if not namespace: + raise ValueError(f"Expected a non-empty value for `namespace` but received {namespace!r}") + if not slug: + raise ValueError(f"Expected a non-empty value for `slug` but received {slug!r}") + return await self._delete( + path_template("/v1/apis/{namespace}/{slug}", **{"namespace": namespace, "slug": slug}), + options=make_request_options(extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout, idempotency_key=idempotency_key), + cast_to=RegistryDeleteApiDocumentResponse, + ) + + async def retrieve_api_document_version( + self, + semver: str, + *, + namespace: str, + slug: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> RegistryRetrieveApiDocumentVersionResponse: + """Get a specific API document version.""" + if not namespace: + raise ValueError(f"Expected a non-empty value for `namespace` but received {namespace!r}") + if not slug: + raise ValueError(f"Expected a non-empty value for `slug` but received {slug!r}") + if not semver: + raise ValueError(f"Expected a non-empty value for `semver` but received {semver!r}") + return await self._get( + path_template("/v1/apis/{namespace}/{slug}/version/{semver}", **{"namespace": namespace, "slug": slug, "semver": semver}), + options=make_request_options(extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout), + cast_to=RegistryRetrieveApiDocumentVersionResponse, + ) + + async def update_api_document_version( + self, + semver: str, + *, + namespace: str, + slug: str, + document: str, + last_known_version_sha: str | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + idempotency_key: str | None = None, + ) -> RegistryUpdateApiDocumentVersionResponse: + """Update the registry file content for an API document version.""" + if not namespace: + raise ValueError(f"Expected a non-empty value for `namespace` but received {namespace!r}") + if not slug: + raise ValueError(f"Expected a non-empty value for `slug` but received {slug!r}") + if not semver: + raise ValueError(f"Expected a non-empty value for `semver` but received {semver!r}") + return await self._patch( + path_template("/v1/apis/{namespace}/{slug}/version/{semver}", **{"namespace": namespace, "slug": slug, "semver": semver}), + body=await async_maybe_transform( + { + "document": document, + "last_known_version_sha": last_known_version_sha, + }, + registry_update_api_document_version_params.RegistryUpdateApiDocumentVersionParams, + ), + options=make_request_options(extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout, idempotency_key=idempotency_key), + cast_to=RegistryUpdateApiDocumentVersionResponse, + ) + + async def delete_api_document_version( + self, + semver: str, + *, + namespace: str, + slug: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + idempotency_key: str | None = None, + ) -> RegistryDeleteApiDocumentVersionResponse: + """Delete a specific API document version.""" + if not namespace: + raise ValueError(f"Expected a non-empty value for `namespace` but received {namespace!r}") + if not slug: + raise ValueError(f"Expected a non-empty value for `slug` but received {slug!r}") + if not semver: + raise ValueError(f"Expected a non-empty value for `semver` but received {semver!r}") + return await self._delete( + path_template("/v1/apis/{namespace}/{slug}/version/{semver}", **{"namespace": namespace, "slug": slug, "semver": semver}), + options=make_request_options(extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout, idempotency_key=idempotency_key), + cast_to=RegistryDeleteApiDocumentVersionResponse, + ) + + async def list_api_document_version_metadata( + self, + semver: str, + *, + namespace: str, + slug: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> RegistryListApiDocumentVersionMetadataResponse: + """Get metadata (uid, content shas, version sha, tags) for a specific API document version.""" + if not namespace: + raise ValueError(f"Expected a non-empty value for `namespace` but received {namespace!r}") + if not slug: + raise ValueError(f"Expected a non-empty value for `slug` but received {slug!r}") + if not semver: + raise ValueError(f"Expected a non-empty value for `semver` but received {semver!r}") + return await self._get( + path_template("/v1/apis/{namespace}/{slug}/version/{semver}/metadata", **{"namespace": namespace, "slug": slug, "semver": semver}), + options=make_request_options(extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout), + cast_to=RegistryListApiDocumentVersionMetadataResponse, + ) + + async def create_api_document_version( + self, + slug: str, + *, + namespace: str, + version: str, + document: str, + force: bool | Omit = omit, + last_known_version_sha: str | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + idempotency_key: str | None = None, + ) -> RegistryCreateApiDocumentVersionResponse: + """Create a new API document version.""" + if not namespace: + raise ValueError(f"Expected a non-empty value for `namespace` but received {namespace!r}") + if not slug: + raise ValueError(f"Expected a non-empty value for `slug` but received {slug!r}") + return await self._post( + path_template("/v1/apis/{namespace}/{slug}/version", **{"namespace": namespace, "slug": slug}), + body=await async_maybe_transform( + { + "version": version, + "document": document, + "force": force, + "last_known_version_sha": last_known_version_sha, + }, + registry_create_api_document_version_params.RegistryCreateApiDocumentVersionParams, + ), + options=make_request_options(extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout, idempotency_key=idempotency_key), + cast_to=RegistryCreateApiDocumentVersionResponse, + ) + + async def create_api_document_access_group( + self, + slug: str, + *, + namespace: str, + access_group_slug: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + idempotency_key: str | None = None, + ) -> RegistryCreateApiDocumentAccessGroupResponse: + """Add an access group to an API document.""" + if not namespace: + raise ValueError(f"Expected a non-empty value for `namespace` but received {namespace!r}") + if not slug: + raise ValueError(f"Expected a non-empty value for `slug` but received {slug!r}") + return await self._post( + path_template("/v1/apis/{namespace}/{slug}/access-group", **{"namespace": namespace, "slug": slug}), + body=await async_maybe_transform( + {"access_group_slug": access_group_slug}, + registry_create_api_document_access_group_params.RegistryCreateApiDocumentAccessGroupParams, + ), + options=make_request_options(extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout, idempotency_key=idempotency_key), + cast_to=RegistryCreateApiDocumentAccessGroupResponse, + ) + + async def delete_api_document_access_group( + self, + slug: str, + *, + namespace: str, + access_group_slug: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + idempotency_key: str | None = None, + ) -> RegistryDeleteApiDocumentAccessGroupResponse: + """Remove an access group from an API document.""" + if not namespace: + raise ValueError(f"Expected a non-empty value for `namespace` but received {namespace!r}") + if not slug: + raise ValueError(f"Expected a non-empty value for `slug` but received {slug!r}") + return await self._delete( + path_template("/v1/apis/{namespace}/{slug}/access-group", **{"namespace": namespace, "slug": slug}), + body=await async_maybe_transform( + {"access_group_slug": access_group_slug}, + registry_delete_api_document_access_group_params.RegistryDeleteApiDocumentAccessGroupParams, + ), + options=make_request_options(extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout, idempotency_key=idempotency_key), + cast_to=RegistryDeleteApiDocumentAccessGroupResponse, + ) + + +class RegistryResourceWithRawResponse: + def __init__(self, registry: RegistryResource) -> None: + self._registry = registry + + self.list_all_api_documents = to_raw_response_wrapper( + registry.list_all_api_documents, + ) + self.list_api_documents = to_raw_response_wrapper( + registry.list_api_documents, + ) + self.create_api_document = to_raw_response_wrapper( + registry.create_api_document, + ) + self.update_api_document = to_raw_response_wrapper( + registry.update_api_document, + ) + self.delete_api_document = to_raw_response_wrapper( + registry.delete_api_document, + ) + self.retrieve_api_document_version = to_raw_response_wrapper( + registry.retrieve_api_document_version, + ) + self.update_api_document_version = to_raw_response_wrapper( + registry.update_api_document_version, + ) + self.delete_api_document_version = to_raw_response_wrapper( + registry.delete_api_document_version, + ) + self.list_api_document_version_metadata = to_raw_response_wrapper( + registry.list_api_document_version_metadata, + ) + self.create_api_document_version = to_raw_response_wrapper( + registry.create_api_document_version, + ) + self.create_api_document_access_group = to_raw_response_wrapper( + registry.create_api_document_access_group, + ) + self.delete_api_document_access_group = to_raw_response_wrapper( + registry.delete_api_document_access_group, + ) + + +class AsyncRegistryResourceWithRawResponse: + def __init__(self, registry: AsyncRegistryResource) -> None: + self._registry = registry + + self.list_all_api_documents = async_to_raw_response_wrapper( + registry.list_all_api_documents, + ) + self.list_api_documents = async_to_raw_response_wrapper( + registry.list_api_documents, + ) + self.create_api_document = async_to_raw_response_wrapper( + registry.create_api_document, + ) + self.update_api_document = async_to_raw_response_wrapper( + registry.update_api_document, + ) + self.delete_api_document = async_to_raw_response_wrapper( + registry.delete_api_document, + ) + self.retrieve_api_document_version = async_to_raw_response_wrapper( + registry.retrieve_api_document_version, + ) + self.update_api_document_version = async_to_raw_response_wrapper( + registry.update_api_document_version, + ) + self.delete_api_document_version = async_to_raw_response_wrapper( + registry.delete_api_document_version, + ) + self.list_api_document_version_metadata = async_to_raw_response_wrapper( + registry.list_api_document_version_metadata, + ) + self.create_api_document_version = async_to_raw_response_wrapper( + registry.create_api_document_version, + ) + self.create_api_document_access_group = async_to_raw_response_wrapper( + registry.create_api_document_access_group, + ) + self.delete_api_document_access_group = async_to_raw_response_wrapper( + registry.delete_api_document_access_group, + ) + + +class RegistryResourceWithStreamingResponse: + def __init__(self, registry: RegistryResource) -> None: + self._registry = registry + + self.list_all_api_documents = to_streamed_response_wrapper( + registry.list_all_api_documents, + ) + self.list_api_documents = to_streamed_response_wrapper( + registry.list_api_documents, + ) + self.create_api_document = to_streamed_response_wrapper( + registry.create_api_document, + ) + self.update_api_document = to_streamed_response_wrapper( + registry.update_api_document, + ) + self.delete_api_document = to_streamed_response_wrapper( + registry.delete_api_document, + ) + self.retrieve_api_document_version = to_streamed_response_wrapper( + registry.retrieve_api_document_version, + ) + self.update_api_document_version = to_streamed_response_wrapper( + registry.update_api_document_version, + ) + self.delete_api_document_version = to_streamed_response_wrapper( + registry.delete_api_document_version, + ) + self.list_api_document_version_metadata = to_streamed_response_wrapper( + registry.list_api_document_version_metadata, + ) + self.create_api_document_version = to_streamed_response_wrapper( + registry.create_api_document_version, + ) + self.create_api_document_access_group = to_streamed_response_wrapper( + registry.create_api_document_access_group, + ) + self.delete_api_document_access_group = to_streamed_response_wrapper( + registry.delete_api_document_access_group, + ) + + +class AsyncRegistryResourceWithStreamingResponse: + def __init__(self, registry: AsyncRegistryResource) -> None: + self._registry = registry + + self.list_all_api_documents = async_to_streamed_response_wrapper( + registry.list_all_api_documents, + ) + self.list_api_documents = async_to_streamed_response_wrapper( + registry.list_api_documents, + ) + self.create_api_document = async_to_streamed_response_wrapper( + registry.create_api_document, + ) + self.update_api_document = async_to_streamed_response_wrapper( + registry.update_api_document, + ) + self.delete_api_document = async_to_streamed_response_wrapper( + registry.delete_api_document, + ) + self.retrieve_api_document_version = async_to_streamed_response_wrapper( + registry.retrieve_api_document_version, + ) + self.update_api_document_version = async_to_streamed_response_wrapper( + registry.update_api_document_version, + ) + self.delete_api_document_version = async_to_streamed_response_wrapper( + registry.delete_api_document_version, + ) + self.list_api_document_version_metadata = async_to_streamed_response_wrapper( + registry.list_api_document_version_metadata, + ) + self.create_api_document_version = async_to_streamed_response_wrapper( + registry.create_api_document_version, + ) + self.create_api_document_access_group = async_to_streamed_response_wrapper( + registry.create_api_document_access_group, + ) + self.delete_api_document_access_group = async_to_streamed_response_wrapper( + registry.delete_api_document_access_group, + ) diff --git a/src/resources/rules.py b/src/resources/rules.py new file mode 100644 index 0000000..a37deb2 --- /dev/null +++ b/src/resources/rules.py @@ -0,0 +1,552 @@ +# File generated from our OpenAPI spec by Scalar. See README.md for details. + +from __future__ import annotations + +import httpx + +from .._types import Body, Omit, Query, Headers, NotGiven, omit, not_given +from .._utils import path_template, maybe_transform, async_maybe_transform +from .._compat import cached_property +from .._resource import SyncAPIResource, AsyncAPIResource +from .._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from .._base_client import make_request_options +from ..types.rule_list_rulesets_response import RuleListRulesetsResponse +from ..types.rule_create_ruleset_response import RuleCreateRulesetResponse +from ..types import rule_create_ruleset_params +from ..types.rule_update_ruleset_response import RuleUpdateRulesetResponse +from ..types import rule_update_ruleset_params +from ..types.rule_delete_ruleset_response import RuleDeleteRulesetResponse +from ..types.rule_retrieve_ruleset_document_response import RuleRetrieveRulesetDocumentResponse +from ..types.rule_create_ruleset_access_group_response import RuleCreateRulesetAccessGroupResponse +from ..types import rule_create_ruleset_access_group_params +from ..types.rule_delete_ruleset_access_group_response import RuleDeleteRulesetAccessGroupResponse +from ..types import rule_delete_ruleset_access_group_params + +__all__ = ["RulesResource", "AsyncRulesResource"] + + +class RulesResource(SyncAPIResource): + + @cached_property + def with_raw_response(self) -> RulesResourceWithRawResponse: + return RulesResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> RulesResourceWithStreamingResponse: + return RulesResourceWithStreamingResponse(self) + + def list_rulesets( + self, + namespace: str, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> RuleListRulesetsResponse: + """List all rulesets in a namespace.""" + if not namespace: + raise ValueError(f"Expected a non-empty value for `namespace` but received {namespace!r}") + return self._get( + path_template("/v1/rulesets/{namespace}", **{"namespace": namespace}), + options=make_request_options(extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout), + cast_to=RuleListRulesetsResponse, + ) + + def create_ruleset( + self, + namespace: str, + *, + title: str, + description: str | Omit = omit, + slug: str, + is_private: bool | Omit = omit, + document: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + idempotency_key: str | None = None, + ) -> RuleCreateRulesetResponse: + """Create a rule in a namespace.""" + if not namespace: + raise ValueError(f"Expected a non-empty value for `namespace` but received {namespace!r}") + return self._post( + path_template("/v1/rulesets/{namespace}", **{"namespace": namespace}), + body=maybe_transform( + { + "title": title, + "description": description, + "slug": slug, + "is_private": is_private, + "document": document, + }, + rule_create_ruleset_params.RuleCreateRulesetParams, + ), + options=make_request_options(extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout, idempotency_key=idempotency_key), + cast_to=RuleCreateRulesetResponse, + ) + + def update_ruleset( + self, + slug: str, + *, + namespace: str, + title: str | Omit = omit, + description: str | Omit = omit, + is_private: bool | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + idempotency_key: str | None = None, + ) -> RuleUpdateRulesetResponse: + """Update rule metadata by slug.""" + if not namespace: + raise ValueError(f"Expected a non-empty value for `namespace` but received {namespace!r}") + if not slug: + raise ValueError(f"Expected a non-empty value for `slug` but received {slug!r}") + return self._patch( + path_template("/v1/rulesets/{namespace}/{slug}", **{"namespace": namespace, "slug": slug}), + body=maybe_transform( + { + "title": title, + "description": description, + "is_private": is_private, + }, + rule_update_ruleset_params.RuleUpdateRulesetParams, + ), + options=make_request_options(extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout, idempotency_key=idempotency_key), + cast_to=RuleUpdateRulesetResponse, + ) + + def delete_ruleset( + self, + slug: str, + *, + namespace: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + idempotency_key: str | None = None, + ) -> RuleDeleteRulesetResponse: + """Delete a rule by slug.""" + if not namespace: + raise ValueError(f"Expected a non-empty value for `namespace` but received {namespace!r}") + if not slug: + raise ValueError(f"Expected a non-empty value for `slug` but received {slug!r}") + return self._delete( + path_template("/v1/rulesets/{namespace}/{slug}", **{"namespace": namespace, "slug": slug}), + options=make_request_options(extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout, idempotency_key=idempotency_key), + cast_to=RuleDeleteRulesetResponse, + ) + + def retrieve_ruleset_document( + self, + slug: str, + *, + namespace: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> RuleRetrieveRulesetDocumentResponse: + """Get a rule document by slug.""" + if not namespace: + raise ValueError(f"Expected a non-empty value for `namespace` but received {namespace!r}") + if not slug: + raise ValueError(f"Expected a non-empty value for `slug` but received {slug!r}") + return self._get( + path_template("/v1/rulesets/{namespace}/{slug}", **{"namespace": namespace, "slug": slug}), + options=make_request_options(extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout), + cast_to=RuleRetrieveRulesetDocumentResponse, + ) + + def create_ruleset_access_group( + self, + slug: str, + *, + namespace: str, + access_group_slug: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + idempotency_key: str | None = None, + ) -> RuleCreateRulesetAccessGroupResponse: + """Grant an access group to a rule.""" + if not namespace: + raise ValueError(f"Expected a non-empty value for `namespace` but received {namespace!r}") + if not slug: + raise ValueError(f"Expected a non-empty value for `slug` but received {slug!r}") + return self._post( + path_template("/v1/rulesets/{namespace}/{slug}/access-group", **{"namespace": namespace, "slug": slug}), + body=maybe_transform( + {"access_group_slug": access_group_slug}, + rule_create_ruleset_access_group_params.RuleCreateRulesetAccessGroupParams, + ), + options=make_request_options(extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout, idempotency_key=idempotency_key), + cast_to=RuleCreateRulesetAccessGroupResponse, + ) + + def delete_ruleset_access_group( + self, + slug: str, + *, + namespace: str, + access_group_slug: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + idempotency_key: str | None = None, + ) -> RuleDeleteRulesetAccessGroupResponse: + """Remove an access group from a rule.""" + if not namespace: + raise ValueError(f"Expected a non-empty value for `namespace` but received {namespace!r}") + if not slug: + raise ValueError(f"Expected a non-empty value for `slug` but received {slug!r}") + return self._delete( + path_template("/v1/rulesets/{namespace}/{slug}/access-group", **{"namespace": namespace, "slug": slug}), + body=maybe_transform( + {"access_group_slug": access_group_slug}, + rule_delete_ruleset_access_group_params.RuleDeleteRulesetAccessGroupParams, + ), + options=make_request_options(extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout, idempotency_key=idempotency_key), + cast_to=RuleDeleteRulesetAccessGroupResponse, + ) + + +class AsyncRulesResource(AsyncAPIResource): + + @cached_property + def with_raw_response(self) -> AsyncRulesResourceWithRawResponse: + return AsyncRulesResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncRulesResourceWithStreamingResponse: + return AsyncRulesResourceWithStreamingResponse(self) + + async def list_rulesets( + self, + namespace: str, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> RuleListRulesetsResponse: + """List all rulesets in a namespace.""" + if not namespace: + raise ValueError(f"Expected a non-empty value for `namespace` but received {namespace!r}") + return await self._get( + path_template("/v1/rulesets/{namespace}", **{"namespace": namespace}), + options=make_request_options(extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout), + cast_to=RuleListRulesetsResponse, + ) + + async def create_ruleset( + self, + namespace: str, + *, + title: str, + description: str | Omit = omit, + slug: str, + is_private: bool | Omit = omit, + document: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + idempotency_key: str | None = None, + ) -> RuleCreateRulesetResponse: + """Create a rule in a namespace.""" + if not namespace: + raise ValueError(f"Expected a non-empty value for `namespace` but received {namespace!r}") + return await self._post( + path_template("/v1/rulesets/{namespace}", **{"namespace": namespace}), + body=await async_maybe_transform( + { + "title": title, + "description": description, + "slug": slug, + "is_private": is_private, + "document": document, + }, + rule_create_ruleset_params.RuleCreateRulesetParams, + ), + options=make_request_options(extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout, idempotency_key=idempotency_key), + cast_to=RuleCreateRulesetResponse, + ) + + async def update_ruleset( + self, + slug: str, + *, + namespace: str, + title: str | Omit = omit, + description: str | Omit = omit, + is_private: bool | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + idempotency_key: str | None = None, + ) -> RuleUpdateRulesetResponse: + """Update rule metadata by slug.""" + if not namespace: + raise ValueError(f"Expected a non-empty value for `namespace` but received {namespace!r}") + if not slug: + raise ValueError(f"Expected a non-empty value for `slug` but received {slug!r}") + return await self._patch( + path_template("/v1/rulesets/{namespace}/{slug}", **{"namespace": namespace, "slug": slug}), + body=await async_maybe_transform( + { + "title": title, + "description": description, + "is_private": is_private, + }, + rule_update_ruleset_params.RuleUpdateRulesetParams, + ), + options=make_request_options(extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout, idempotency_key=idempotency_key), + cast_to=RuleUpdateRulesetResponse, + ) + + async def delete_ruleset( + self, + slug: str, + *, + namespace: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + idempotency_key: str | None = None, + ) -> RuleDeleteRulesetResponse: + """Delete a rule by slug.""" + if not namespace: + raise ValueError(f"Expected a non-empty value for `namespace` but received {namespace!r}") + if not slug: + raise ValueError(f"Expected a non-empty value for `slug` but received {slug!r}") + return await self._delete( + path_template("/v1/rulesets/{namespace}/{slug}", **{"namespace": namespace, "slug": slug}), + options=make_request_options(extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout, idempotency_key=idempotency_key), + cast_to=RuleDeleteRulesetResponse, + ) + + async def retrieve_ruleset_document( + self, + slug: str, + *, + namespace: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> RuleRetrieveRulesetDocumentResponse: + """Get a rule document by slug.""" + if not namespace: + raise ValueError(f"Expected a non-empty value for `namespace` but received {namespace!r}") + if not slug: + raise ValueError(f"Expected a non-empty value for `slug` but received {slug!r}") + return await self._get( + path_template("/v1/rulesets/{namespace}/{slug}", **{"namespace": namespace, "slug": slug}), + options=make_request_options(extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout), + cast_to=RuleRetrieveRulesetDocumentResponse, + ) + + async def create_ruleset_access_group( + self, + slug: str, + *, + namespace: str, + access_group_slug: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + idempotency_key: str | None = None, + ) -> RuleCreateRulesetAccessGroupResponse: + """Grant an access group to a rule.""" + if not namespace: + raise ValueError(f"Expected a non-empty value for `namespace` but received {namespace!r}") + if not slug: + raise ValueError(f"Expected a non-empty value for `slug` but received {slug!r}") + return await self._post( + path_template("/v1/rulesets/{namespace}/{slug}/access-group", **{"namespace": namespace, "slug": slug}), + body=await async_maybe_transform( + {"access_group_slug": access_group_slug}, + rule_create_ruleset_access_group_params.RuleCreateRulesetAccessGroupParams, + ), + options=make_request_options(extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout, idempotency_key=idempotency_key), + cast_to=RuleCreateRulesetAccessGroupResponse, + ) + + async def delete_ruleset_access_group( + self, + slug: str, + *, + namespace: str, + access_group_slug: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + idempotency_key: str | None = None, + ) -> RuleDeleteRulesetAccessGroupResponse: + """Remove an access group from a rule.""" + if not namespace: + raise ValueError(f"Expected a non-empty value for `namespace` but received {namespace!r}") + if not slug: + raise ValueError(f"Expected a non-empty value for `slug` but received {slug!r}") + return await self._delete( + path_template("/v1/rulesets/{namespace}/{slug}/access-group", **{"namespace": namespace, "slug": slug}), + body=await async_maybe_transform( + {"access_group_slug": access_group_slug}, + rule_delete_ruleset_access_group_params.RuleDeleteRulesetAccessGroupParams, + ), + options=make_request_options(extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout, idempotency_key=idempotency_key), + cast_to=RuleDeleteRulesetAccessGroupResponse, + ) + + +class RulesResourceWithRawResponse: + def __init__(self, rules: RulesResource) -> None: + self._rules = rules + + self.list_rulesets = to_raw_response_wrapper( + rules.list_rulesets, + ) + self.create_ruleset = to_raw_response_wrapper( + rules.create_ruleset, + ) + self.update_ruleset = to_raw_response_wrapper( + rules.update_ruleset, + ) + self.delete_ruleset = to_raw_response_wrapper( + rules.delete_ruleset, + ) + self.retrieve_ruleset_document = to_raw_response_wrapper( + rules.retrieve_ruleset_document, + ) + self.create_ruleset_access_group = to_raw_response_wrapper( + rules.create_ruleset_access_group, + ) + self.delete_ruleset_access_group = to_raw_response_wrapper( + rules.delete_ruleset_access_group, + ) + + +class AsyncRulesResourceWithRawResponse: + def __init__(self, rules: AsyncRulesResource) -> None: + self._rules = rules + + self.list_rulesets = async_to_raw_response_wrapper( + rules.list_rulesets, + ) + self.create_ruleset = async_to_raw_response_wrapper( + rules.create_ruleset, + ) + self.update_ruleset = async_to_raw_response_wrapper( + rules.update_ruleset, + ) + self.delete_ruleset = async_to_raw_response_wrapper( + rules.delete_ruleset, + ) + self.retrieve_ruleset_document = async_to_raw_response_wrapper( + rules.retrieve_ruleset_document, + ) + self.create_ruleset_access_group = async_to_raw_response_wrapper( + rules.create_ruleset_access_group, + ) + self.delete_ruleset_access_group = async_to_raw_response_wrapper( + rules.delete_ruleset_access_group, + ) + + +class RulesResourceWithStreamingResponse: + def __init__(self, rules: RulesResource) -> None: + self._rules = rules + + self.list_rulesets = to_streamed_response_wrapper( + rules.list_rulesets, + ) + self.create_ruleset = to_streamed_response_wrapper( + rules.create_ruleset, + ) + self.update_ruleset = to_streamed_response_wrapper( + rules.update_ruleset, + ) + self.delete_ruleset = to_streamed_response_wrapper( + rules.delete_ruleset, + ) + self.retrieve_ruleset_document = to_streamed_response_wrapper( + rules.retrieve_ruleset_document, + ) + self.create_ruleset_access_group = to_streamed_response_wrapper( + rules.create_ruleset_access_group, + ) + self.delete_ruleset_access_group = to_streamed_response_wrapper( + rules.delete_ruleset_access_group, + ) + + +class AsyncRulesResourceWithStreamingResponse: + def __init__(self, rules: AsyncRulesResource) -> None: + self._rules = rules + + self.list_rulesets = async_to_streamed_response_wrapper( + rules.list_rulesets, + ) + self.create_ruleset = async_to_streamed_response_wrapper( + rules.create_ruleset, + ) + self.update_ruleset = async_to_streamed_response_wrapper( + rules.update_ruleset, + ) + self.delete_ruleset = async_to_streamed_response_wrapper( + rules.delete_ruleset, + ) + self.retrieve_ruleset_document = async_to_streamed_response_wrapper( + rules.retrieve_ruleset_document, + ) + self.create_ruleset_access_group = async_to_streamed_response_wrapper( + rules.create_ruleset_access_group, + ) + self.delete_ruleset_access_group = async_to_streamed_response_wrapper( + rules.delete_ruleset_access_group, + ) diff --git a/src/resources/scalar_docs.py b/src/resources/scalar_docs.py new file mode 100644 index 0000000..ef55373 --- /dev/null +++ b/src/resources/scalar_docs.py @@ -0,0 +1,249 @@ +# File generated from our OpenAPI spec by Scalar. See README.md for details. + +from __future__ import annotations + +import httpx + +from typing import List + +from .._types import Body, Omit, Query, Headers, NotGiven, omit, not_given +from .._utils import path_template, maybe_transform, async_maybe_transform +from .._compat import cached_property +from .._resource import SyncAPIResource, AsyncAPIResource +from .._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from .._base_client import make_request_options +from ..types.scalar_doc_list_guides_response import ScalarDocListGuidesResponse +from ..types.scalar_doc_create_guide_response import ScalarDocCreateGuideResponse +from ..types import scalar_doc_create_guide_params +from ..types.scalar_doc_publish_guide_response import ScalarDocPublishGuideResponse + +__all__ = ["ScalarDocsResource", "AsyncScalarDocsResource"] + + +class ScalarDocsResource(SyncAPIResource): + + @cached_property + def with_raw_response(self) -> ScalarDocsResourceWithRawResponse: + return ScalarDocsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> ScalarDocsResourceWithStreamingResponse: + return ScalarDocsResourceWithStreamingResponse(self) + + def list_guides( + self, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> ScalarDocListGuidesResponse: + """List all guide projects.""" + return self._get( + "/v1/guides", + options=make_request_options(extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout), + cast_to=ScalarDocListGuidesResponse, + ) + + def create_guide( + self, + *, + name: str, + slug: str | Omit = omit, + is_private: bool, + allowed_users: List[str], + allowed_domains: List[str], + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + idempotency_key: str | None = None, + ) -> ScalarDocCreateGuideResponse: + """Create a guide project.""" + return self._post( + "/v1/guides", + body=maybe_transform( + { + "name": name, + "slug": slug, + "is_private": is_private, + "allowed_users": allowed_users, + "allowed_domains": allowed_domains, + }, + scalar_doc_create_guide_params.ScalarDocCreateGuideParams, + ), + options=make_request_options(extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout, idempotency_key=idempotency_key), + cast_to=ScalarDocCreateGuideResponse, + ) + + def publish_guide( + self, + slug: str, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + idempotency_key: str | None = None, + ) -> ScalarDocPublishGuideResponse: + """Start a new publish process.""" + if not slug: + raise ValueError(f"Expected a non-empty value for `slug` but received {slug!r}") + return self._post( + path_template("/v1/guides/{slug}/publish", **{"slug": slug}), + options=make_request_options(extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout, idempotency_key=idempotency_key), + cast_to=ScalarDocPublishGuideResponse, + ) + + +class AsyncScalarDocsResource(AsyncAPIResource): + + @cached_property + def with_raw_response(self) -> AsyncScalarDocsResourceWithRawResponse: + return AsyncScalarDocsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncScalarDocsResourceWithStreamingResponse: + return AsyncScalarDocsResourceWithStreamingResponse(self) + + async def list_guides( + self, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> ScalarDocListGuidesResponse: + """List all guide projects.""" + return await self._get( + "/v1/guides", + options=make_request_options(extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout), + cast_to=ScalarDocListGuidesResponse, + ) + + async def create_guide( + self, + *, + name: str, + slug: str | Omit = omit, + is_private: bool, + allowed_users: List[str], + allowed_domains: List[str], + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + idempotency_key: str | None = None, + ) -> ScalarDocCreateGuideResponse: + """Create a guide project.""" + return await self._post( + "/v1/guides", + body=await async_maybe_transform( + { + "name": name, + "slug": slug, + "is_private": is_private, + "allowed_users": allowed_users, + "allowed_domains": allowed_domains, + }, + scalar_doc_create_guide_params.ScalarDocCreateGuideParams, + ), + options=make_request_options(extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout, idempotency_key=idempotency_key), + cast_to=ScalarDocCreateGuideResponse, + ) + + async def publish_guide( + self, + slug: str, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + idempotency_key: str | None = None, + ) -> ScalarDocPublishGuideResponse: + """Start a new publish process.""" + if not slug: + raise ValueError(f"Expected a non-empty value for `slug` but received {slug!r}") + return await self._post( + path_template("/v1/guides/{slug}/publish", **{"slug": slug}), + options=make_request_options(extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout, idempotency_key=idempotency_key), + cast_to=ScalarDocPublishGuideResponse, + ) + + +class ScalarDocsResourceWithRawResponse: + def __init__(self, scalar_docs: ScalarDocsResource) -> None: + self._scalar_docs = scalar_docs + + self.list_guides = to_raw_response_wrapper( + scalar_docs.list_guides, + ) + self.create_guide = to_raw_response_wrapper( + scalar_docs.create_guide, + ) + self.publish_guide = to_raw_response_wrapper( + scalar_docs.publish_guide, + ) + + +class AsyncScalarDocsResourceWithRawResponse: + def __init__(self, scalar_docs: AsyncScalarDocsResource) -> None: + self._scalar_docs = scalar_docs + + self.list_guides = async_to_raw_response_wrapper( + scalar_docs.list_guides, + ) + self.create_guide = async_to_raw_response_wrapper( + scalar_docs.create_guide, + ) + self.publish_guide = async_to_raw_response_wrapper( + scalar_docs.publish_guide, + ) + + +class ScalarDocsResourceWithStreamingResponse: + def __init__(self, scalar_docs: ScalarDocsResource) -> None: + self._scalar_docs = scalar_docs + + self.list_guides = to_streamed_response_wrapper( + scalar_docs.list_guides, + ) + self.create_guide = to_streamed_response_wrapper( + scalar_docs.create_guide, + ) + self.publish_guide = to_streamed_response_wrapper( + scalar_docs.publish_guide, + ) + + +class AsyncScalarDocsResourceWithStreamingResponse: + def __init__(self, scalar_docs: AsyncScalarDocsResource) -> None: + self._scalar_docs = scalar_docs + + self.list_guides = async_to_streamed_response_wrapper( + scalar_docs.list_guides, + ) + self.create_guide = async_to_streamed_response_wrapper( + scalar_docs.create_guide, + ) + self.publish_guide = async_to_streamed_response_wrapper( + scalar_docs.publish_guide, + ) diff --git a/src/resources/schemas/__init__.py b/src/resources/schemas/__init__.py new file mode 100644 index 0000000..bee0515 --- /dev/null +++ b/src/resources/schemas/__init__.py @@ -0,0 +1,19 @@ +# File generated from our OpenAPI spec by Scalar. See README.md for details. + +from .schemas import ( + SchemasResource, + AsyncSchemasResource, + SchemasResourceWithRawResponse, + AsyncSchemasResourceWithRawResponse, + SchemasResourceWithStreamingResponse, + AsyncSchemasResourceWithStreamingResponse, +) + +__all__ = [ + "SchemasResource", + "AsyncSchemasResource", + "SchemasResourceWithRawResponse", + "AsyncSchemasResourceWithRawResponse", + "SchemasResourceWithStreamingResponse", + "AsyncSchemasResourceWithStreamingResponse", +] diff --git a/src/resources/schemas/access_group.py b/src/resources/schemas/access_group.py new file mode 100644 index 0000000..5ef4064 --- /dev/null +++ b/src/resources/schemas/access_group.py @@ -0,0 +1,209 @@ +# File generated from our OpenAPI spec by Scalar. See README.md for details. + +from __future__ import annotations + +import httpx + +from ..._types import Body, Omit, Query, Headers, NotGiven, omit, not_given +from ..._utils import path_template, maybe_transform, async_maybe_transform +from ..._compat import cached_property +from ..._resource import SyncAPIResource, AsyncAPIResource +from ..._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ..._base_client import make_request_options +from ...types.schemas.access_group_create_schema_response import AccessGroupCreateSchemaResponse +from ...types.schemas import access_group_create_schema_params +from ...types.schemas.access_group_delete_schema_response import AccessGroupDeleteSchemaResponse +from ...types.schemas import access_group_delete_schema_params + +__all__ = ["AccessGroupResource", "AsyncAccessGroupResource"] + + +class AccessGroupResource(SyncAPIResource): + + @cached_property + def with_raw_response(self) -> AccessGroupResourceWithRawResponse: + return AccessGroupResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AccessGroupResourceWithStreamingResponse: + return AccessGroupResourceWithStreamingResponse(self) + + def create_schema( + self, + slug: str, + *, + namespace: str, + access_group_slug: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + idempotency_key: str | None = None, + ) -> AccessGroupCreateSchemaResponse: + """Add an access group to a schema.""" + if not namespace: + raise ValueError(f"Expected a non-empty value for `namespace` but received {namespace!r}") + if not slug: + raise ValueError(f"Expected a non-empty value for `slug` but received {slug!r}") + return self._post( + path_template("/v1/schemas/{namespace}/{slug}/access-group", **{"namespace": namespace, "slug": slug}), + body=maybe_transform( + {"access_group_slug": access_group_slug}, + access_group_create_schema_params.AccessGroupCreateSchemaParams, + ), + options=make_request_options(extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout, idempotency_key=idempotency_key), + cast_to=AccessGroupCreateSchemaResponse, + ) + + def delete_schema( + self, + slug: str, + *, + namespace: str, + access_group_slug: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + idempotency_key: str | None = None, + ) -> AccessGroupDeleteSchemaResponse: + """Remove an access group from a schema.""" + if not namespace: + raise ValueError(f"Expected a non-empty value for `namespace` but received {namespace!r}") + if not slug: + raise ValueError(f"Expected a non-empty value for `slug` but received {slug!r}") + return self._delete( + path_template("/v1/schemas/{namespace}/{slug}/access-group", **{"namespace": namespace, "slug": slug}), + body=maybe_transform( + {"access_group_slug": access_group_slug}, + access_group_delete_schema_params.AccessGroupDeleteSchemaParams, + ), + options=make_request_options(extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout, idempotency_key=idempotency_key), + cast_to=AccessGroupDeleteSchemaResponse, + ) + + +class AsyncAccessGroupResource(AsyncAPIResource): + + @cached_property + def with_raw_response(self) -> AsyncAccessGroupResourceWithRawResponse: + return AsyncAccessGroupResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncAccessGroupResourceWithStreamingResponse: + return AsyncAccessGroupResourceWithStreamingResponse(self) + + async def create_schema( + self, + slug: str, + *, + namespace: str, + access_group_slug: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + idempotency_key: str | None = None, + ) -> AccessGroupCreateSchemaResponse: + """Add an access group to a schema.""" + if not namespace: + raise ValueError(f"Expected a non-empty value for `namespace` but received {namespace!r}") + if not slug: + raise ValueError(f"Expected a non-empty value for `slug` but received {slug!r}") + return await self._post( + path_template("/v1/schemas/{namespace}/{slug}/access-group", **{"namespace": namespace, "slug": slug}), + body=await async_maybe_transform( + {"access_group_slug": access_group_slug}, + access_group_create_schema_params.AccessGroupCreateSchemaParams, + ), + options=make_request_options(extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout, idempotency_key=idempotency_key), + cast_to=AccessGroupCreateSchemaResponse, + ) + + async def delete_schema( + self, + slug: str, + *, + namespace: str, + access_group_slug: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + idempotency_key: str | None = None, + ) -> AccessGroupDeleteSchemaResponse: + """Remove an access group from a schema.""" + if not namespace: + raise ValueError(f"Expected a non-empty value for `namespace` but received {namespace!r}") + if not slug: + raise ValueError(f"Expected a non-empty value for `slug` but received {slug!r}") + return await self._delete( + path_template("/v1/schemas/{namespace}/{slug}/access-group", **{"namespace": namespace, "slug": slug}), + body=await async_maybe_transform( + {"access_group_slug": access_group_slug}, + access_group_delete_schema_params.AccessGroupDeleteSchemaParams, + ), + options=make_request_options(extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout, idempotency_key=idempotency_key), + cast_to=AccessGroupDeleteSchemaResponse, + ) + + +class AccessGroupResourceWithRawResponse: + def __init__(self, access_group: AccessGroupResource) -> None: + self._access_group = access_group + + self.create_schema = to_raw_response_wrapper( + access_group.create_schema, + ) + self.delete_schema = to_raw_response_wrapper( + access_group.delete_schema, + ) + + +class AsyncAccessGroupResourceWithRawResponse: + def __init__(self, access_group: AsyncAccessGroupResource) -> None: + self._access_group = access_group + + self.create_schema = async_to_raw_response_wrapper( + access_group.create_schema, + ) + self.delete_schema = async_to_raw_response_wrapper( + access_group.delete_schema, + ) + + +class AccessGroupResourceWithStreamingResponse: + def __init__(self, access_group: AccessGroupResource) -> None: + self._access_group = access_group + + self.create_schema = to_streamed_response_wrapper( + access_group.create_schema, + ) + self.delete_schema = to_streamed_response_wrapper( + access_group.delete_schema, + ) + + +class AsyncAccessGroupResourceWithStreamingResponse: + def __init__(self, access_group: AsyncAccessGroupResource) -> None: + self._access_group = access_group + + self.create_schema = async_to_streamed_response_wrapper( + access_group.create_schema, + ) + self.delete_schema = async_to_streamed_response_wrapper( + access_group.delete_schema, + ) diff --git a/src/resources/schemas/schemas.py b/src/resources/schemas/schemas.py new file mode 100644 index 0000000..45feea1 --- /dev/null +++ b/src/resources/schemas/schemas.py @@ -0,0 +1,417 @@ +# File generated from our OpenAPI spec by Scalar. See README.md for details. + +from __future__ import annotations + +import httpx + +from ..._types import Body, Omit, Query, Headers, NotGiven, omit, not_given +from ..._utils import path_template, maybe_transform, async_maybe_transform +from ..._compat import cached_property +from ..._resource import SyncAPIResource, AsyncAPIResource +from ..._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ..._base_client import make_request_options +from .version import ( + VersionResource, + AsyncVersionResource, +) +from .access_group import ( + AccessGroupResource, + AsyncAccessGroupResource, +) +from ...types.schema_list_response import SchemaListResponse +from ...types.schema_create_response import SchemaCreateResponse +from ...types import schema_create_params +from ...types.schema_update_response import SchemaUpdateResponse +from ...types import schema_update_params +from ...types.schema_delete_response import SchemaDeleteResponse + +__all__ = ["SchemasResource", "AsyncSchemasResource"] + + +class SchemasResource(SyncAPIResource): + + @cached_property + def version(self) -> VersionResource: + return VersionResource(self._client) + + @cached_property + def access_group(self) -> AccessGroupResource: + return AccessGroupResource(self._client) + + @cached_property + def with_raw_response(self) -> SchemasResourceWithRawResponse: + return SchemasResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> SchemasResourceWithStreamingResponse: + return SchemasResourceWithStreamingResponse(self) + + def list( + self, + namespace: str, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> SchemaListResponse: + """List schemas in a namespace.""" + if not namespace: + raise ValueError(f"Expected a non-empty value for `namespace` but received {namespace!r}") + return self._get( + path_template("/v1/schemas/{namespace}", **{"namespace": namespace}), + options=make_request_options(extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout), + cast_to=SchemaListResponse, + ) + + def create( + self, + namespace: str, + *, + title: str, + description: str | Omit = omit, + version: str, + slug: str, + is_private: bool | Omit = omit, + document: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + idempotency_key: str | None = None, + ) -> SchemaCreateResponse: + """Create a schema in a namespace.""" + if not namespace: + raise ValueError(f"Expected a non-empty value for `namespace` but received {namespace!r}") + return self._post( + path_template("/v1/schemas/{namespace}", **{"namespace": namespace}), + body=maybe_transform( + { + "title": title, + "description": description, + "version": version, + "slug": slug, + "is_private": is_private, + "document": document, + }, + schema_create_params.SchemaCreateParams, + ), + options=make_request_options(extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout, idempotency_key=idempotency_key), + cast_to=SchemaCreateResponse, + ) + + def update( + self, + slug: str, + *, + namespace: str, + title: str | Omit = omit, + description: str | Omit = omit, + is_private: bool | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + idempotency_key: str | None = None, + ) -> SchemaUpdateResponse: + """Update schema metadata.""" + if not namespace: + raise ValueError(f"Expected a non-empty value for `namespace` but received {namespace!r}") + if not slug: + raise ValueError(f"Expected a non-empty value for `slug` but received {slug!r}") + return self._patch( + path_template("/v1/schemas/{namespace}/{slug}", **{"namespace": namespace, "slug": slug}), + body=maybe_transform( + { + "title": title, + "description": description, + "is_private": is_private, + }, + schema_update_params.SchemaUpdateParams, + ), + options=make_request_options(extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout, idempotency_key=idempotency_key), + cast_to=SchemaUpdateResponse, + ) + + def delete( + self, + slug: str, + *, + namespace: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + idempotency_key: str | None = None, + ) -> SchemaDeleteResponse: + """Delete a schema and all related versions.""" + if not namespace: + raise ValueError(f"Expected a non-empty value for `namespace` but received {namespace!r}") + if not slug: + raise ValueError(f"Expected a non-empty value for `slug` but received {slug!r}") + return self._delete( + path_template("/v1/schemas/{namespace}/{slug}", **{"namespace": namespace, "slug": slug}), + options=make_request_options(extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout, idempotency_key=idempotency_key), + cast_to=SchemaDeleteResponse, + ) + + +class AsyncSchemasResource(AsyncAPIResource): + + @cached_property + def version(self) -> AsyncVersionResource: + return AsyncVersionResource(self._client) + + @cached_property + def access_group(self) -> AsyncAccessGroupResource: + return AsyncAccessGroupResource(self._client) + + @cached_property + def with_raw_response(self) -> AsyncSchemasResourceWithRawResponse: + return AsyncSchemasResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncSchemasResourceWithStreamingResponse: + return AsyncSchemasResourceWithStreamingResponse(self) + + async def list( + self, + namespace: str, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> SchemaListResponse: + """List schemas in a namespace.""" + if not namespace: + raise ValueError(f"Expected a non-empty value for `namespace` but received {namespace!r}") + return await self._get( + path_template("/v1/schemas/{namespace}", **{"namespace": namespace}), + options=make_request_options(extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout), + cast_to=SchemaListResponse, + ) + + async def create( + self, + namespace: str, + *, + title: str, + description: str | Omit = omit, + version: str, + slug: str, + is_private: bool | Omit = omit, + document: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + idempotency_key: str | None = None, + ) -> SchemaCreateResponse: + """Create a schema in a namespace.""" + if not namespace: + raise ValueError(f"Expected a non-empty value for `namespace` but received {namespace!r}") + return await self._post( + path_template("/v1/schemas/{namespace}", **{"namespace": namespace}), + body=await async_maybe_transform( + { + "title": title, + "description": description, + "version": version, + "slug": slug, + "is_private": is_private, + "document": document, + }, + schema_create_params.SchemaCreateParams, + ), + options=make_request_options(extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout, idempotency_key=idempotency_key), + cast_to=SchemaCreateResponse, + ) + + async def update( + self, + slug: str, + *, + namespace: str, + title: str | Omit = omit, + description: str | Omit = omit, + is_private: bool | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + idempotency_key: str | None = None, + ) -> SchemaUpdateResponse: + """Update schema metadata.""" + if not namespace: + raise ValueError(f"Expected a non-empty value for `namespace` but received {namespace!r}") + if not slug: + raise ValueError(f"Expected a non-empty value for `slug` but received {slug!r}") + return await self._patch( + path_template("/v1/schemas/{namespace}/{slug}", **{"namespace": namespace, "slug": slug}), + body=await async_maybe_transform( + { + "title": title, + "description": description, + "is_private": is_private, + }, + schema_update_params.SchemaUpdateParams, + ), + options=make_request_options(extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout, idempotency_key=idempotency_key), + cast_to=SchemaUpdateResponse, + ) + + async def delete( + self, + slug: str, + *, + namespace: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + idempotency_key: str | None = None, + ) -> SchemaDeleteResponse: + """Delete a schema and all related versions.""" + if not namespace: + raise ValueError(f"Expected a non-empty value for `namespace` but received {namespace!r}") + if not slug: + raise ValueError(f"Expected a non-empty value for `slug` but received {slug!r}") + return await self._delete( + path_template("/v1/schemas/{namespace}/{slug}", **{"namespace": namespace, "slug": slug}), + options=make_request_options(extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout, idempotency_key=idempotency_key), + cast_to=SchemaDeleteResponse, + ) + + +class SchemasResourceWithRawResponse: + def __init__(self, schemas: SchemasResource) -> None: + self._schemas = schemas + + self.list = to_raw_response_wrapper( + schemas.list, + ) + self.create = to_raw_response_wrapper( + schemas.create, + ) + self.update = to_raw_response_wrapper( + schemas.update, + ) + self.delete = to_raw_response_wrapper( + schemas.delete, + ) + + @cached_property + def version(self) -> "VersionResourceWithRawResponse": + from .version import VersionResourceWithRawResponse + return VersionResourceWithRawResponse(self._schemas.version) + + @cached_property + def access_group(self) -> "AccessGroupResourceWithRawResponse": + from .access_group import AccessGroupResourceWithRawResponse + return AccessGroupResourceWithRawResponse(self._schemas.access_group) + + +class AsyncSchemasResourceWithRawResponse: + def __init__(self, schemas: AsyncSchemasResource) -> None: + self._schemas = schemas + + self.list = async_to_raw_response_wrapper( + schemas.list, + ) + self.create = async_to_raw_response_wrapper( + schemas.create, + ) + self.update = async_to_raw_response_wrapper( + schemas.update, + ) + self.delete = async_to_raw_response_wrapper( + schemas.delete, + ) + + @cached_property + def version(self) -> "AsyncVersionResourceWithRawResponse": + from .version import AsyncVersionResourceWithRawResponse + return AsyncVersionResourceWithRawResponse(self._schemas.version) + + @cached_property + def access_group(self) -> "AsyncAccessGroupResourceWithRawResponse": + from .access_group import AsyncAccessGroupResourceWithRawResponse + return AsyncAccessGroupResourceWithRawResponse(self._schemas.access_group) + + +class SchemasResourceWithStreamingResponse: + def __init__(self, schemas: SchemasResource) -> None: + self._schemas = schemas + + self.list = to_streamed_response_wrapper( + schemas.list, + ) + self.create = to_streamed_response_wrapper( + schemas.create, + ) + self.update = to_streamed_response_wrapper( + schemas.update, + ) + self.delete = to_streamed_response_wrapper( + schemas.delete, + ) + + @cached_property + def version(self) -> "VersionResourceWithStreamingResponse": + from .version import VersionResourceWithStreamingResponse + return VersionResourceWithStreamingResponse(self._schemas.version) + + @cached_property + def access_group(self) -> "AccessGroupResourceWithStreamingResponse": + from .access_group import AccessGroupResourceWithStreamingResponse + return AccessGroupResourceWithStreamingResponse(self._schemas.access_group) + + +class AsyncSchemasResourceWithStreamingResponse: + def __init__(self, schemas: AsyncSchemasResource) -> None: + self._schemas = schemas + + self.list = async_to_streamed_response_wrapper( + schemas.list, + ) + self.create = async_to_streamed_response_wrapper( + schemas.create, + ) + self.update = async_to_streamed_response_wrapper( + schemas.update, + ) + self.delete = async_to_streamed_response_wrapper( + schemas.delete, + ) + + @cached_property + def version(self) -> "AsyncVersionResourceWithStreamingResponse": + from .version import AsyncVersionResourceWithStreamingResponse + return AsyncVersionResourceWithStreamingResponse(self._schemas.version) + + @cached_property + def access_group(self) -> "AsyncAccessGroupResourceWithStreamingResponse": + from .access_group import AsyncAccessGroupResourceWithStreamingResponse + return AsyncAccessGroupResourceWithStreamingResponse(self._schemas.access_group) diff --git a/src/resources/schemas/version.py b/src/resources/schemas/version.py new file mode 100644 index 0000000..9c2e01f --- /dev/null +++ b/src/resources/schemas/version.py @@ -0,0 +1,277 @@ +# File generated from our OpenAPI spec by Scalar. See README.md for details. + +from __future__ import annotations + +import httpx + +from ..._types import Body, Omit, Query, Headers, NotGiven, omit, not_given +from ..._utils import path_template, maybe_transform, async_maybe_transform +from ..._compat import cached_property +from ..._resource import SyncAPIResource, AsyncAPIResource +from ..._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ..._base_client import make_request_options +from ...types.schemas.version_retrieve_schema_response import VersionRetrieveSchemaResponse +from ...types.schemas.version_delete_schema_response import VersionDeleteSchemaResponse +from ...types.schemas.version_create_schema_response import VersionCreateSchemaResponse +from ...types.schemas import version_create_schema_params + +__all__ = ["VersionResource", "AsyncVersionResource"] + + +class VersionResource(SyncAPIResource): + + @cached_property + def with_raw_response(self) -> VersionResourceWithRawResponse: + return VersionResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> VersionResourceWithStreamingResponse: + return VersionResourceWithStreamingResponse(self) + + def retrieve_schema( + self, + semver: str, + *, + namespace: str, + slug: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> VersionRetrieveSchemaResponse: + """Get a specific schema version document.""" + if not namespace: + raise ValueError(f"Expected a non-empty value for `namespace` but received {namespace!r}") + if not slug: + raise ValueError(f"Expected a non-empty value for `slug` but received {slug!r}") + if not semver: + raise ValueError(f"Expected a non-empty value for `semver` but received {semver!r}") + return self._get( + path_template("/v1/schemas/{namespace}/{slug}/version/{semver}", **{"namespace": namespace, "slug": slug, "semver": semver}), + options=make_request_options(extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout), + cast_to=VersionRetrieveSchemaResponse, + ) + + def delete_schema( + self, + semver: str, + *, + namespace: str, + slug: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + idempotency_key: str | None = None, + ) -> VersionDeleteSchemaResponse: + """Delete a schema version.""" + if not namespace: + raise ValueError(f"Expected a non-empty value for `namespace` but received {namespace!r}") + if not slug: + raise ValueError(f"Expected a non-empty value for `slug` but received {slug!r}") + if not semver: + raise ValueError(f"Expected a non-empty value for `semver` but received {semver!r}") + return self._delete( + path_template("/v1/schemas/{namespace}/{slug}/version/{semver}", **{"namespace": namespace, "slug": slug, "semver": semver}), + options=make_request_options(extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout, idempotency_key=idempotency_key), + cast_to=VersionDeleteSchemaResponse, + ) + + def create_schema( + self, + slug: str, + *, + namespace: str, + version: str, + document: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + idempotency_key: str | None = None, + ) -> VersionCreateSchemaResponse: + """Create a schema version.""" + if not namespace: + raise ValueError(f"Expected a non-empty value for `namespace` but received {namespace!r}") + if not slug: + raise ValueError(f"Expected a non-empty value for `slug` but received {slug!r}") + return self._post( + path_template("/v1/schemas/{namespace}/{slug}/version", **{"namespace": namespace, "slug": slug}), + body=maybe_transform( + { + "version": version, + "document": document, + }, + version_create_schema_params.VersionCreateSchemaParams, + ), + options=make_request_options(extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout, idempotency_key=idempotency_key), + cast_to=VersionCreateSchemaResponse, + ) + + +class AsyncVersionResource(AsyncAPIResource): + + @cached_property + def with_raw_response(self) -> AsyncVersionResourceWithRawResponse: + return AsyncVersionResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncVersionResourceWithStreamingResponse: + return AsyncVersionResourceWithStreamingResponse(self) + + async def retrieve_schema( + self, + semver: str, + *, + namespace: str, + slug: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> VersionRetrieveSchemaResponse: + """Get a specific schema version document.""" + if not namespace: + raise ValueError(f"Expected a non-empty value for `namespace` but received {namespace!r}") + if not slug: + raise ValueError(f"Expected a non-empty value for `slug` but received {slug!r}") + if not semver: + raise ValueError(f"Expected a non-empty value for `semver` but received {semver!r}") + return await self._get( + path_template("/v1/schemas/{namespace}/{slug}/version/{semver}", **{"namespace": namespace, "slug": slug, "semver": semver}), + options=make_request_options(extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout), + cast_to=VersionRetrieveSchemaResponse, + ) + + async def delete_schema( + self, + semver: str, + *, + namespace: str, + slug: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + idempotency_key: str | None = None, + ) -> VersionDeleteSchemaResponse: + """Delete a schema version.""" + if not namespace: + raise ValueError(f"Expected a non-empty value for `namespace` but received {namespace!r}") + if not slug: + raise ValueError(f"Expected a non-empty value for `slug` but received {slug!r}") + if not semver: + raise ValueError(f"Expected a non-empty value for `semver` but received {semver!r}") + return await self._delete( + path_template("/v1/schemas/{namespace}/{slug}/version/{semver}", **{"namespace": namespace, "slug": slug, "semver": semver}), + options=make_request_options(extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout, idempotency_key=idempotency_key), + cast_to=VersionDeleteSchemaResponse, + ) + + async def create_schema( + self, + slug: str, + *, + namespace: str, + version: str, + document: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + idempotency_key: str | None = None, + ) -> VersionCreateSchemaResponse: + """Create a schema version.""" + if not namespace: + raise ValueError(f"Expected a non-empty value for `namespace` but received {namespace!r}") + if not slug: + raise ValueError(f"Expected a non-empty value for `slug` but received {slug!r}") + return await self._post( + path_template("/v1/schemas/{namespace}/{slug}/version", **{"namespace": namespace, "slug": slug}), + body=await async_maybe_transform( + { + "version": version, + "document": document, + }, + version_create_schema_params.VersionCreateSchemaParams, + ), + options=make_request_options(extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout, idempotency_key=idempotency_key), + cast_to=VersionCreateSchemaResponse, + ) + + +class VersionResourceWithRawResponse: + def __init__(self, version: VersionResource) -> None: + self._version = version + + self.retrieve_schema = to_raw_response_wrapper( + version.retrieve_schema, + ) + self.delete_schema = to_raw_response_wrapper( + version.delete_schema, + ) + self.create_schema = to_raw_response_wrapper( + version.create_schema, + ) + + +class AsyncVersionResourceWithRawResponse: + def __init__(self, version: AsyncVersionResource) -> None: + self._version = version + + self.retrieve_schema = async_to_raw_response_wrapper( + version.retrieve_schema, + ) + self.delete_schema = async_to_raw_response_wrapper( + version.delete_schema, + ) + self.create_schema = async_to_raw_response_wrapper( + version.create_schema, + ) + + +class VersionResourceWithStreamingResponse: + def __init__(self, version: VersionResource) -> None: + self._version = version + + self.retrieve_schema = to_streamed_response_wrapper( + version.retrieve_schema, + ) + self.delete_schema = to_streamed_response_wrapper( + version.delete_schema, + ) + self.create_schema = to_streamed_response_wrapper( + version.create_schema, + ) + + +class AsyncVersionResourceWithStreamingResponse: + def __init__(self, version: AsyncVersionResource) -> None: + self._version = version + + self.retrieve_schema = async_to_streamed_response_wrapper( + version.retrieve_schema, + ) + self.delete_schema = async_to_streamed_response_wrapper( + version.delete_schema, + ) + self.create_schema = async_to_streamed_response_wrapper( + version.create_schema, + ) diff --git a/src/resources/teams.py b/src/resources/teams.py new file mode 100644 index 0000000..4b1a3e8 --- /dev/null +++ b/src/resources/teams.py @@ -0,0 +1,112 @@ +# File generated from our OpenAPI spec by Scalar. See README.md for details. + +from __future__ import annotations + +import httpx + +from .._types import Body, Omit, Query, Headers, NotGiven, omit, not_given +from .._utils import path_template, maybe_transform, async_maybe_transform +from .._compat import cached_property +from .._resource import SyncAPIResource, AsyncAPIResource +from .._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from .._base_client import make_request_options +from ..types.team_list_response import TeamListResponse + +__all__ = ["TeamsResource", "AsyncTeamsResource"] + + +class TeamsResource(SyncAPIResource): + + @cached_property + def with_raw_response(self) -> TeamsResourceWithRawResponse: + return TeamsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> TeamsResourceWithStreamingResponse: + return TeamsResourceWithStreamingResponse(self) + + def list( + self, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TeamListResponse: + """List all available teams""" + return self._get( + "/v1/teams", + options=make_request_options(extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout), + cast_to=TeamListResponse, + ) + + +class AsyncTeamsResource(AsyncAPIResource): + + @cached_property + def with_raw_response(self) -> AsyncTeamsResourceWithRawResponse: + return AsyncTeamsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncTeamsResourceWithStreamingResponse: + return AsyncTeamsResourceWithStreamingResponse(self) + + async def list( + self, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TeamListResponse: + """List all available teams""" + return await self._get( + "/v1/teams", + options=make_request_options(extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout), + cast_to=TeamListResponse, + ) + + +class TeamsResourceWithRawResponse: + def __init__(self, teams: TeamsResource) -> None: + self._teams = teams + + self.list = to_raw_response_wrapper( + teams.list, + ) + + +class AsyncTeamsResourceWithRawResponse: + def __init__(self, teams: AsyncTeamsResource) -> None: + self._teams = teams + + self.list = async_to_raw_response_wrapper( + teams.list, + ) + + +class TeamsResourceWithStreamingResponse: + def __init__(self, teams: TeamsResource) -> None: + self._teams = teams + + self.list = to_streamed_response_wrapper( + teams.list, + ) + + +class AsyncTeamsResourceWithStreamingResponse: + def __init__(self, teams: AsyncTeamsResource) -> None: + self._teams = teams + + self.list = async_to_streamed_response_wrapper( + teams.list, + ) diff --git a/src/resources/themes.py b/src/resources/themes.py new file mode 100644 index 0000000..3cefa68 --- /dev/null +++ b/src/resources/themes.py @@ -0,0 +1,436 @@ +# File generated from our OpenAPI spec by Scalar. See README.md for details. + +from __future__ import annotations + +import httpx + +from .._types import Body, Omit, Query, Headers, NotGiven, omit, not_given +from .._utils import path_template, maybe_transform, async_maybe_transform +from .._compat import cached_property +from .._resource import SyncAPIResource, AsyncAPIResource +from .._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from .._base_client import make_request_options +from ..types.theme_list_response import ThemeListResponse +from ..types.theme_create_response import ThemeCreateResponse +from ..types import theme_create_params +from ..types.theme_update_response import ThemeUpdateResponse +from ..types import theme_update_params +from ..types.theme_replace_document_response import ThemeReplaceDocumentResponse +from ..types import theme_replace_document_params +from ..types.theme_delete_response import ThemeDeleteResponse +from ..types.theme_retrieve_response import ThemeRetrieveResponse + +__all__ = ["ThemesResource", "AsyncThemesResource"] + + +class ThemesResource(SyncAPIResource): + + @cached_property + def with_raw_response(self) -> ThemesResourceWithRawResponse: + return ThemesResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> ThemesResourceWithStreamingResponse: + return ThemesResourceWithStreamingResponse(self) + + def list( + self, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> ThemeListResponse: + """List all team themes.""" + return self._get( + "/v1/themes", + options=make_request_options(extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout), + cast_to=ThemeListResponse, + ) + + def create( + self, + *, + name: str, + description: str | Omit = omit, + slug: str, + document: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + idempotency_key: str | None = None, + ) -> ThemeCreateResponse: + """Create a team theme.""" + return self._post( + "/v1/themes", + body=maybe_transform( + { + "name": name, + "description": description, + "slug": slug, + "document": document, + }, + theme_create_params.ThemeCreateParams, + ), + options=make_request_options(extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout, idempotency_key=idempotency_key), + cast_to=ThemeCreateResponse, + ) + + def update( + self, + slug: str, + *, + name: str | Omit = omit, + description: str | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + idempotency_key: str | None = None, + ) -> ThemeUpdateResponse: + """Update theme metadata.""" + if not slug: + raise ValueError(f"Expected a non-empty value for `slug` but received {slug!r}") + return self._patch( + path_template("/v1/themes/{slug}", **{"slug": slug}), + body=maybe_transform( + { + "name": name, + "description": description, + }, + theme_update_params.ThemeUpdateParams, + ), + options=make_request_options(extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout, idempotency_key=idempotency_key), + cast_to=ThemeUpdateResponse, + ) + + def replace_document( + self, + slug: str, + *, + document: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + idempotency_key: str | None = None, + ) -> ThemeReplaceDocumentResponse: + """Replace the theme document.""" + if not slug: + raise ValueError(f"Expected a non-empty value for `slug` but received {slug!r}") + return self._put( + path_template("/v1/themes/{slug}", **{"slug": slug}), + body=maybe_transform( + {"document": document}, + theme_replace_document_params.ThemeReplaceDocumentParams, + ), + options=make_request_options(extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout, idempotency_key=idempotency_key), + cast_to=ThemeReplaceDocumentResponse, + ) + + def delete( + self, + slug: str, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + idempotency_key: str | None = None, + ) -> ThemeDeleteResponse: + """Delete a theme by slug.""" + if not slug: + raise ValueError(f"Expected a non-empty value for `slug` but received {slug!r}") + return self._delete( + path_template("/v1/themes/{slug}", **{"slug": slug}), + options=make_request_options(extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout, idempotency_key=idempotency_key), + cast_to=ThemeDeleteResponse, + ) + + def retrieve( + self, + slug: str, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> ThemeRetrieveResponse: + """Get the theme document by slug.""" + if not slug: + raise ValueError(f"Expected a non-empty value for `slug` but received {slug!r}") + return self._get( + path_template("/v1/themes/{slug}", **{"slug": slug}), + options=make_request_options(extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout), + cast_to=ThemeRetrieveResponse, + ) + + +class AsyncThemesResource(AsyncAPIResource): + + @cached_property + def with_raw_response(self) -> AsyncThemesResourceWithRawResponse: + return AsyncThemesResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncThemesResourceWithStreamingResponse: + return AsyncThemesResourceWithStreamingResponse(self) + + async def list( + self, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> ThemeListResponse: + """List all team themes.""" + return await self._get( + "/v1/themes", + options=make_request_options(extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout), + cast_to=ThemeListResponse, + ) + + async def create( + self, + *, + name: str, + description: str | Omit = omit, + slug: str, + document: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + idempotency_key: str | None = None, + ) -> ThemeCreateResponse: + """Create a team theme.""" + return await self._post( + "/v1/themes", + body=await async_maybe_transform( + { + "name": name, + "description": description, + "slug": slug, + "document": document, + }, + theme_create_params.ThemeCreateParams, + ), + options=make_request_options(extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout, idempotency_key=idempotency_key), + cast_to=ThemeCreateResponse, + ) + + async def update( + self, + slug: str, + *, + name: str | Omit = omit, + description: str | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + idempotency_key: str | None = None, + ) -> ThemeUpdateResponse: + """Update theme metadata.""" + if not slug: + raise ValueError(f"Expected a non-empty value for `slug` but received {slug!r}") + return await self._patch( + path_template("/v1/themes/{slug}", **{"slug": slug}), + body=await async_maybe_transform( + { + "name": name, + "description": description, + }, + theme_update_params.ThemeUpdateParams, + ), + options=make_request_options(extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout, idempotency_key=idempotency_key), + cast_to=ThemeUpdateResponse, + ) + + async def replace_document( + self, + slug: str, + *, + document: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + idempotency_key: str | None = None, + ) -> ThemeReplaceDocumentResponse: + """Replace the theme document.""" + if not slug: + raise ValueError(f"Expected a non-empty value for `slug` but received {slug!r}") + return await self._put( + path_template("/v1/themes/{slug}", **{"slug": slug}), + body=await async_maybe_transform( + {"document": document}, + theme_replace_document_params.ThemeReplaceDocumentParams, + ), + options=make_request_options(extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout, idempotency_key=idempotency_key), + cast_to=ThemeReplaceDocumentResponse, + ) + + async def delete( + self, + slug: str, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + idempotency_key: str | None = None, + ) -> ThemeDeleteResponse: + """Delete a theme by slug.""" + if not slug: + raise ValueError(f"Expected a non-empty value for `slug` but received {slug!r}") + return await self._delete( + path_template("/v1/themes/{slug}", **{"slug": slug}), + options=make_request_options(extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout, idempotency_key=idempotency_key), + cast_to=ThemeDeleteResponse, + ) + + async def retrieve( + self, + slug: str, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> ThemeRetrieveResponse: + """Get the theme document by slug.""" + if not slug: + raise ValueError(f"Expected a non-empty value for `slug` but received {slug!r}") + return await self._get( + path_template("/v1/themes/{slug}", **{"slug": slug}), + options=make_request_options(extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout), + cast_to=ThemeRetrieveResponse, + ) + + +class ThemesResourceWithRawResponse: + def __init__(self, themes: ThemesResource) -> None: + self._themes = themes + + self.list = to_raw_response_wrapper( + themes.list, + ) + self.create = to_raw_response_wrapper( + themes.create, + ) + self.update = to_raw_response_wrapper( + themes.update, + ) + self.replace_document = to_raw_response_wrapper( + themes.replace_document, + ) + self.delete = to_raw_response_wrapper( + themes.delete, + ) + self.retrieve = to_raw_response_wrapper( + themes.retrieve, + ) + + +class AsyncThemesResourceWithRawResponse: + def __init__(self, themes: AsyncThemesResource) -> None: + self._themes = themes + + self.list = async_to_raw_response_wrapper( + themes.list, + ) + self.create = async_to_raw_response_wrapper( + themes.create, + ) + self.update = async_to_raw_response_wrapper( + themes.update, + ) + self.replace_document = async_to_raw_response_wrapper( + themes.replace_document, + ) + self.delete = async_to_raw_response_wrapper( + themes.delete, + ) + self.retrieve = async_to_raw_response_wrapper( + themes.retrieve, + ) + + +class ThemesResourceWithStreamingResponse: + def __init__(self, themes: ThemesResource) -> None: + self._themes = themes + + self.list = to_streamed_response_wrapper( + themes.list, + ) + self.create = to_streamed_response_wrapper( + themes.create, + ) + self.update = to_streamed_response_wrapper( + themes.update, + ) + self.replace_document = to_streamed_response_wrapper( + themes.replace_document, + ) + self.delete = to_streamed_response_wrapper( + themes.delete, + ) + self.retrieve = to_streamed_response_wrapper( + themes.retrieve, + ) + + +class AsyncThemesResourceWithStreamingResponse: + def __init__(self, themes: AsyncThemesResource) -> None: + self._themes = themes + + self.list = async_to_streamed_response_wrapper( + themes.list, + ) + self.create = async_to_streamed_response_wrapper( + themes.create, + ) + self.update = async_to_streamed_response_wrapper( + themes.update, + ) + self.replace_document = async_to_streamed_response_wrapper( + themes.replace_document, + ) + self.delete = async_to_streamed_response_wrapper( + themes.delete, + ) + self.retrieve = async_to_streamed_response_wrapper( + themes.retrieve, + ) diff --git a/src/types/_400.py b/src/types/_400.py new file mode 100644 index 0000000..d2a35a0 --- /dev/null +++ b/src/types/_400.py @@ -0,0 +1,13 @@ +# File generated from our OpenAPI spec by Scalar. See README.md for details. + + +from .._models import BaseModel + +__all__ = ["_400"] + + +class _400(BaseModel): + + message: str + + code: str diff --git a/src/types/_401.py b/src/types/_401.py new file mode 100644 index 0000000..1d7e2e3 --- /dev/null +++ b/src/types/_401.py @@ -0,0 +1,13 @@ +# File generated from our OpenAPI spec by Scalar. See README.md for details. + + +from .._models import BaseModel + +__all__ = ["_401"] + + +class _401(BaseModel): + + message: str + + code: str diff --git a/src/types/_403.py b/src/types/_403.py new file mode 100644 index 0000000..80cf160 --- /dev/null +++ b/src/types/_403.py @@ -0,0 +1,13 @@ +# File generated from our OpenAPI spec by Scalar. See README.md for details. + + +from .._models import BaseModel + +__all__ = ["_403"] + + +class _403(BaseModel): + + message: str + + code: str diff --git a/src/types/_404.py b/src/types/_404.py new file mode 100644 index 0000000..40cc635 --- /dev/null +++ b/src/types/_404.py @@ -0,0 +1,13 @@ +# File generated from our OpenAPI spec by Scalar. See README.md for details. + + +from .._models import BaseModel + +__all__ = ["_404"] + + +class _404(BaseModel): + + message: str + + code: str diff --git a/src/types/_422.py b/src/types/_422.py new file mode 100644 index 0000000..b3191c8 --- /dev/null +++ b/src/types/_422.py @@ -0,0 +1,13 @@ +# File generated from our OpenAPI spec by Scalar. See README.md for details. + + +from .._models import BaseModel + +__all__ = ["_422"] + + +class _422(BaseModel): + + message: str + + code: str diff --git a/src/types/_500.py b/src/types/_500.py new file mode 100644 index 0000000..0888545 --- /dev/null +++ b/src/types/_500.py @@ -0,0 +1,13 @@ +# File generated from our OpenAPI spec by Scalar. See README.md for details. + + +from .._models import BaseModel + +__all__ = ["_500"] + + +class _500(BaseModel): + + message: str + + code: str diff --git a/src/types/__init__.py b/src/types/__init__.py new file mode 100644 index 0000000..2f3be9d --- /dev/null +++ b/src/types/__init__.py @@ -0,0 +1,96 @@ +# File generated from our OpenAPI spec by Scalar. See README.md for details. + +from __future__ import annotations + +from ._400 import _400 as _400 +from ._401 import _401 as _401 +from ._403 import _403 as _403 +from ._404 import _404 as _404 +from ._422 import _422 as _422 +from ._500 import _500 as _500 +from .api_document import ApiDocument as ApiDocument +from .nanoid import Nanoid as Nanoid +from .version import Version as Version +from .slug import Slug as Slug +from .namespace import Namespace as Namespace +from .managed_doc_version import ManagedDocVersion as ManagedDocVersion +from .method import Method as Method +from .access_group import AccessGroup as AccessGroup +from .schema import Schema as Schema +from .managed_schema_version import ManagedSchemaVersion as ManagedSchemaVersion +from .timestamp import Timestamp as Timestamp +from .uid import Uid as Uid +from .login_portal_email import LoginPortalEmail as LoginPortalEmail +from .login_portal_page import LoginPortalPage as LoginPortalPage +from .login_portal import LoginPortal as LoginPortal +from .rule import Rule as Rule +from .theme import Theme as Theme +from .team import Team as Team +from .team_name import TeamName as TeamName +from .team_image import TeamImage as TeamImage +from .github_project import GithubProject as GithubProject +from .active_deployment import ActiveDeployment as ActiveDeployment +from .github_project_repository import GithubProjectRepository as GithubProjectRepository +from .email import Email as Email +from .team_summary import TeamSummary as TeamSummary +from .user import User as User +from .registry_list_all_api_documents_response import RegistryListAllApiDocumentsResponse as RegistryListAllApiDocumentsResponse +from .registry_list_api_documents_response import RegistryListApiDocumentsResponse as RegistryListApiDocumentsResponse +from .registry_create_api_document_response import RegistryCreateApiDocumentResponse as RegistryCreateApiDocumentResponse +from .registry_create_api_document_params import RegistryCreateApiDocumentParams as RegistryCreateApiDocumentParams +from .registry_update_api_document_response import RegistryUpdateApiDocumentResponse as RegistryUpdateApiDocumentResponse +from .registry_update_api_document_params import RegistryUpdateApiDocumentParams as RegistryUpdateApiDocumentParams +from .registry_delete_api_document_response import RegistryDeleteApiDocumentResponse as RegistryDeleteApiDocumentResponse +from .registry_retrieve_api_document_version_response import RegistryRetrieveApiDocumentVersionResponse as RegistryRetrieveApiDocumentVersionResponse +from .registry_update_api_document_version_response import RegistryUpdateApiDocumentVersionResponse as RegistryUpdateApiDocumentVersionResponse +from .registry_update_api_document_version_params import RegistryUpdateApiDocumentVersionParams as RegistryUpdateApiDocumentVersionParams +from .registry_delete_api_document_version_response import RegistryDeleteApiDocumentVersionResponse as RegistryDeleteApiDocumentVersionResponse +from .registry_list_api_document_version_metadata_response import RegistryListApiDocumentVersionMetadataResponse as RegistryListApiDocumentVersionMetadataResponse +from .registry_create_api_document_version_response import RegistryCreateApiDocumentVersionResponse as RegistryCreateApiDocumentVersionResponse +from .registry_create_api_document_version_params import RegistryCreateApiDocumentVersionParams as RegistryCreateApiDocumentVersionParams +from .registry_create_api_document_access_group_response import RegistryCreateApiDocumentAccessGroupResponse as RegistryCreateApiDocumentAccessGroupResponse +from .registry_create_api_document_access_group_params import RegistryCreateApiDocumentAccessGroupParams as RegistryCreateApiDocumentAccessGroupParams +from .registry_delete_api_document_access_group_response import RegistryDeleteApiDocumentAccessGroupResponse as RegistryDeleteApiDocumentAccessGroupResponse +from .registry_delete_api_document_access_group_params import RegistryDeleteApiDocumentAccessGroupParams as RegistryDeleteApiDocumentAccessGroupParams +from .schema_list_response import SchemaListResponse as SchemaListResponse +from .schema_create_response import SchemaCreateResponse as SchemaCreateResponse +from .schema_create_params import SchemaCreateParams as SchemaCreateParams +from .schema_update_response import SchemaUpdateResponse as SchemaUpdateResponse +from .schema_update_params import SchemaUpdateParams as SchemaUpdateParams +from .schema_delete_response import SchemaDeleteResponse as SchemaDeleteResponse +from .login_portal_retrieve_response import LoginPortalRetrieveResponse as LoginPortalRetrieveResponse +from .login_portal_update_response import LoginPortalUpdateResponse as LoginPortalUpdateResponse +from .login_portal_update_params import LoginPortalUpdateParams as LoginPortalUpdateParams +from .login_portal_delete_response import LoginPortalDeleteResponse as LoginPortalDeleteResponse +from .login_portal_create_response import LoginPortalCreateResponse as LoginPortalCreateResponse +from .login_portal_create_params import LoginPortalCreateParams as LoginPortalCreateParams +from .login_portal_list_response import LoginPortalListResponse as LoginPortalListResponse +from .rule_list_rulesets_response import RuleListRulesetsResponse as RuleListRulesetsResponse +from .rule_create_ruleset_response import RuleCreateRulesetResponse as RuleCreateRulesetResponse +from .rule_create_ruleset_params import RuleCreateRulesetParams as RuleCreateRulesetParams +from .rule_update_ruleset_response import RuleUpdateRulesetResponse as RuleUpdateRulesetResponse +from .rule_update_ruleset_params import RuleUpdateRulesetParams as RuleUpdateRulesetParams +from .rule_delete_ruleset_response import RuleDeleteRulesetResponse as RuleDeleteRulesetResponse +from .rule_retrieve_ruleset_document_response import RuleRetrieveRulesetDocumentResponse as RuleRetrieveRulesetDocumentResponse +from .rule_create_ruleset_access_group_response import RuleCreateRulesetAccessGroupResponse as RuleCreateRulesetAccessGroupResponse +from .rule_create_ruleset_access_group_params import RuleCreateRulesetAccessGroupParams as RuleCreateRulesetAccessGroupParams +from .rule_delete_ruleset_access_group_response import RuleDeleteRulesetAccessGroupResponse as RuleDeleteRulesetAccessGroupResponse +from .rule_delete_ruleset_access_group_params import RuleDeleteRulesetAccessGroupParams as RuleDeleteRulesetAccessGroupParams +from .theme_list_response import ThemeListResponse as ThemeListResponse +from .theme_create_response import ThemeCreateResponse as ThemeCreateResponse +from .theme_create_params import ThemeCreateParams as ThemeCreateParams +from .theme_update_response import ThemeUpdateResponse as ThemeUpdateResponse +from .theme_update_params import ThemeUpdateParams as ThemeUpdateParams +from .theme_replace_document_response import ThemeReplaceDocumentResponse as ThemeReplaceDocumentResponse +from .theme_replace_document_params import ThemeReplaceDocumentParams as ThemeReplaceDocumentParams +from .theme_delete_response import ThemeDeleteResponse as ThemeDeleteResponse +from .theme_retrieve_response import ThemeRetrieveResponse as ThemeRetrieveResponse +from .team_list_response import TeamListResponse as TeamListResponse +from .scalar_doc_list_guides_response import ScalarDocListGuidesResponse as ScalarDocListGuidesResponse +from .scalar_doc_create_guide_response import ScalarDocCreateGuideResponse as ScalarDocCreateGuideResponse +from .scalar_doc_create_guide_params import ScalarDocCreateGuideParams as ScalarDocCreateGuideParams +from .scalar_doc_publish_guide_response import ScalarDocPublishGuideResponse as ScalarDocPublishGuideResponse +from .namespace_list_response import NamespaceListResponse as NamespaceListResponse +from .authentication_exchange_personal_token_response import AuthenticationExchangePersonalTokenResponse as AuthenticationExchangePersonalTokenResponse +from .authentication_exchange_personal_token_params import AuthenticationExchangePersonalTokenParams as AuthenticationExchangePersonalTokenParams +from .authentication_list_current_user_response import AuthenticationListCurrentUserResponse as AuthenticationListCurrentUserResponse diff --git a/src/types/access_group.py b/src/types/access_group.py new file mode 100644 index 0000000..ed3f7dc --- /dev/null +++ b/src/types/access_group.py @@ -0,0 +1,12 @@ +# File generated from our OpenAPI spec by Scalar. See README.md for details. + + +from .._models import BaseModel +from .slug import Slug + +__all__ = ["AccessGroup"] + + +class AccessGroup(BaseModel): + + accessGroupSlug: Slug diff --git a/src/types/active_deployment.py b/src/types/active_deployment.py new file mode 100644 index 0000000..e01a470 --- /dev/null +++ b/src/types/active_deployment.py @@ -0,0 +1,16 @@ +# File generated from our OpenAPI spec by Scalar. See README.md for details. + + +from .._models import BaseModel +from .timestamp import Timestamp + +__all__ = ["ActiveDeployment"] + + +class ActiveDeployment(BaseModel): + + uid: str + + domain: str + + publishedAt: Timestamp diff --git a/src/types/api_document.py b/src/types/api_document.py new file mode 100644 index 0000000..70de5b2 --- /dev/null +++ b/src/types/api_document.py @@ -0,0 +1,33 @@ +# File generated from our OpenAPI spec by Scalar. See README.md for details. + +from typing import List + +from .._models import BaseModel +from .nanoid import Nanoid +from .version import Version +from .slug import Slug +from .namespace import Namespace +from .managed_doc_version import ManagedDocVersion + +__all__ = ["ApiDocument"] + + +class ApiDocument(BaseModel): + + uid: Nanoid + + version: Version + + title: str + + slug: Slug + + description: str + + namespace: Namespace + + isPrivate: bool + + tags: str + + versions: List[ManagedDocVersion] diff --git a/src/types/authentication_exchange_personal_token_params.py b/src/types/authentication_exchange_personal_token_params.py new file mode 100644 index 0000000..1cb5507 --- /dev/null +++ b/src/types/authentication_exchange_personal_token_params.py @@ -0,0 +1,14 @@ +# File generated from our OpenAPI spec by Scalar. See README.md for details. + +from __future__ import annotations + +from typing import Annotated +from typing_extensions import Required, TypedDict +from .._utils import PropertyInfo + +__all__ = ["AuthenticationExchangePersonalTokenParams"] + + +class AuthenticationExchangePersonalTokenParams(TypedDict, total=False): + + personal_token: Required[Annotated[str, PropertyInfo(alias="personalToken")]] diff --git a/src/types/authentication_exchange_personal_token_response.py b/src/types/authentication_exchange_personal_token_response.py new file mode 100644 index 0000000..aa3b416 --- /dev/null +++ b/src/types/authentication_exchange_personal_token_response.py @@ -0,0 +1,9 @@ +# File generated from our OpenAPI spec by Scalar. See README.md for details. + +from __future__ import annotations + +from typing_extensions import TypeAlias + +__all__ = ["AuthenticationExchangePersonalTokenResponse"] + +AuthenticationExchangePersonalTokenResponse: TypeAlias = object diff --git a/src/types/authentication_list_current_user_response.py b/src/types/authentication_list_current_user_response.py new file mode 100644 index 0000000..db44af3 --- /dev/null +++ b/src/types/authentication_list_current_user_response.py @@ -0,0 +1,10 @@ +# File generated from our OpenAPI spec by Scalar. See README.md for details. + +from __future__ import annotations + +from typing_extensions import TypeAlias +from .user import User + +__all__ = ["AuthenticationListCurrentUserResponse"] + +AuthenticationListCurrentUserResponse: TypeAlias = User diff --git a/src/types/email.py b/src/types/email.py new file mode 100644 index 0000000..716d068 --- /dev/null +++ b/src/types/email.py @@ -0,0 +1,9 @@ +# File generated from our OpenAPI spec by Scalar. See README.md for details. + +from __future__ import annotations + +from typing_extensions import TypeAlias + +__all__ = ["Email"] + +Email: TypeAlias = str diff --git a/src/types/github_project.py b/src/types/github_project.py new file mode 100644 index 0000000..cef63ad --- /dev/null +++ b/src/types/github_project.py @@ -0,0 +1,49 @@ +# File generated from our OpenAPI spec by Scalar. See README.md for details. + +from typing import Optional, Union + +from .._models import BaseModel +from .nanoid import Nanoid +from .timestamp import Timestamp +from .active_deployment import ActiveDeployment +from .slug import Slug +from .github_project_repository import GithubProjectRepository + +__all__ = ["GithubProject"] + + +class GithubProject(BaseModel): + + uid: Nanoid + + createdAt: Timestamp + + updatedAt: Timestamp + + name: str + + activeDeployment: Optional[Union[ActiveDeployment, None]] = None + + lastPublished: Optional[Union[Timestamp, None]] = None + + lastPublishedUid: Optional[Union[str, None]] = None + + loginPortalUid: str + + activeThemeId: str + + typesenseId: Optional[float] = None + + isPrivate: bool + + agentEnabled: bool + + accessGroups: str + + slug: Slug + + publishStatus: str + + publishMessage: str + + repository: Optional[Union[GithubProjectRepository, None]] = None diff --git a/src/types/github_project_repository.py b/src/types/github_project_repository.py new file mode 100644 index 0000000..be96f6f --- /dev/null +++ b/src/types/github_project_repository.py @@ -0,0 +1,27 @@ +# File generated from our OpenAPI spec by Scalar. See README.md for details. + + +from .._models import BaseModel + +__all__ = ["GithubProjectRepository"] + + +class GithubProjectRepository(BaseModel): + + linkedBy: str + + id: float + + name: str + + configPath: str + + branch: str + + publishOnMerge: bool + + publishPreviews: bool + + prComments: bool + + expired: bool diff --git a/src/types/login_portal.py b/src/types/login_portal.py new file mode 100644 index 0000000..997cb1e --- /dev/null +++ b/src/types/login_portal.py @@ -0,0 +1,17 @@ +# File generated from our OpenAPI spec by Scalar. See README.md for details. + + +from .._models import BaseModel +from .nanoid import Nanoid +from .slug import Slug + +__all__ = ["LoginPortal"] + + +class LoginPortal(BaseModel): + + uid: Nanoid + + title: str + + slug: Slug diff --git a/src/types/login_portal_create_params.py b/src/types/login_portal_create_params.py new file mode 100644 index 0000000..e127d5e --- /dev/null +++ b/src/types/login_portal_create_params.py @@ -0,0 +1,18 @@ +# File generated from our OpenAPI spec by Scalar. See README.md for details. + +from __future__ import annotations + +from typing_extensions import Required, TypedDict + +__all__ = ["LoginPortalCreateParams"] + + +class LoginPortalCreateParams(TypedDict, total=False): + + title: Required[str] + + slug: Required[str] + + email: Required[object] + + page: Required[object] diff --git a/src/types/login_portal_create_response.py b/src/types/login_portal_create_response.py new file mode 100644 index 0000000..7c2ae74 --- /dev/null +++ b/src/types/login_portal_create_response.py @@ -0,0 +1,10 @@ +# File generated from our OpenAPI spec by Scalar. See README.md for details. + +from __future__ import annotations + +from typing_extensions import TypeAlias +from .uid import Uid + +__all__ = ["LoginPortalCreateResponse"] + +LoginPortalCreateResponse: TypeAlias = Uid diff --git a/src/types/login_portal_delete_response.py b/src/types/login_portal_delete_response.py new file mode 100644 index 0000000..a7446a7 --- /dev/null +++ b/src/types/login_portal_delete_response.py @@ -0,0 +1,9 @@ +# File generated from our OpenAPI spec by Scalar. See README.md for details. + +from __future__ import annotations + +from typing_extensions import TypeAlias + +__all__ = ["LoginPortalDeleteResponse"] + +LoginPortalDeleteResponse: TypeAlias = None diff --git a/src/types/login_portal_email.py b/src/types/login_portal_email.py new file mode 100644 index 0000000..cd89f91 --- /dev/null +++ b/src/types/login_portal_email.py @@ -0,0 +1,31 @@ +# File generated from our OpenAPI spec by Scalar. See README.md for details. + + +from .._models import BaseModel + +__all__ = ["LoginPortalEmail"] + + +class LoginPortalEmail(BaseModel): + + logo: str + + logoSize: str + + buttonText: str + + message: str + + title: str + + mainColor: str + + mainBackground: str + + cardColor: str + + cardBackground: str + + buttonColor: str + + buttonBackground: str diff --git a/src/types/login_portal_list_response.py b/src/types/login_portal_list_response.py new file mode 100644 index 0000000..b7ed0ca --- /dev/null +++ b/src/types/login_portal_list_response.py @@ -0,0 +1,11 @@ +# File generated from our OpenAPI spec by Scalar. See README.md for details. + +from __future__ import annotations + +from typing import List +from typing_extensions import TypeAlias +from .login_portal import LoginPortal + +__all__ = ["LoginPortalListResponse"] + +LoginPortalListResponse: TypeAlias = List[LoginPortal] diff --git a/src/types/login_portal_page.py b/src/types/login_portal_page.py new file mode 100644 index 0000000..803f48e --- /dev/null +++ b/src/types/login_portal_page.py @@ -0,0 +1,37 @@ +# File generated from our OpenAPI spec by Scalar. See README.md for details. + + +from .._models import BaseModel + +__all__ = ["LoginPortalPage"] + + +class LoginPortalPage(BaseModel): + + title: str + + description: str + + head: str + + script: str + + theme: str + + companyName: str + + logo: str + + logoURL: str + + favicon: str + + termsLink: str + + privacyLink: str + + formTitle: str + + formDescription: str + + formImage: str diff --git a/src/types/login_portal_retrieve_response.py b/src/types/login_portal_retrieve_response.py new file mode 100644 index 0000000..9c35326 --- /dev/null +++ b/src/types/login_portal_retrieve_response.py @@ -0,0 +1,9 @@ +# File generated from our OpenAPI spec by Scalar. See README.md for details. + +from __future__ import annotations + +from typing_extensions import TypeAlias + +__all__ = ["LoginPortalRetrieveResponse"] + +LoginPortalRetrieveResponse: TypeAlias = object diff --git a/src/types/login_portal_update_params.py b/src/types/login_portal_update_params.py new file mode 100644 index 0000000..8832ac2 --- /dev/null +++ b/src/types/login_portal_update_params.py @@ -0,0 +1,12 @@ +# File generated from our OpenAPI spec by Scalar. See README.md for details. + +from __future__ import annotations + +from typing_extensions import TypedDict + +__all__ = ["LoginPortalUpdateParams"] + + +class LoginPortalUpdateParams(TypedDict, total=False): + + title: str diff --git a/src/types/login_portal_update_response.py b/src/types/login_portal_update_response.py new file mode 100644 index 0000000..7a5b913 --- /dev/null +++ b/src/types/login_portal_update_response.py @@ -0,0 +1,9 @@ +# File generated from our OpenAPI spec by Scalar. See README.md for details. + +from __future__ import annotations + +from typing_extensions import TypeAlias + +__all__ = ["LoginPortalUpdateResponse"] + +LoginPortalUpdateResponse: TypeAlias = None diff --git a/src/types/managed_doc_version.py b/src/types/managed_doc_version.py new file mode 100644 index 0000000..0bb4345 --- /dev/null +++ b/src/types/managed_doc_version.py @@ -0,0 +1,33 @@ +# File generated from our OpenAPI spec by Scalar. See README.md for details. + +from typing import List, Optional, Union +from typing_extensions import Literal + +from .._models import BaseModel +from .nanoid import Nanoid +from .version import Version + +__all__ = ["ManagedDocVersion"] + + +class ManagedDocVersion(BaseModel): + + uid: Nanoid + + createdAt: float + + version: Version + + upgraded: bool + + embedStatus: Optional[Union[Literal["complete", "failed"], None]] = None + + tags: List[str] + + tools: Optional[List[object]] = None + + yamlSha: Optional[str] = None + + jsonSha: Optional[str] = None + + versionSha: Optional[str] = None diff --git a/src/types/managed_schema_version.py b/src/types/managed_schema_version.py new file mode 100644 index 0000000..45cf82f --- /dev/null +++ b/src/types/managed_schema_version.py @@ -0,0 +1,20 @@ +# File generated from our OpenAPI spec by Scalar. See README.md for details. + + +from .._models import BaseModel +from .nanoid import Nanoid +from .timestamp import Timestamp +from .version import Version + +__all__ = ["ManagedSchemaVersion"] + + +class ManagedSchemaVersion(BaseModel): + + uid: Nanoid + + createdAt: Timestamp + + updatedAt: Timestamp + + version: Version diff --git a/src/types/method.py b/src/types/method.py new file mode 100644 index 0000000..bbfeba4 --- /dev/null +++ b/src/types/method.py @@ -0,0 +1,9 @@ +# File generated from our OpenAPI spec by Scalar. See README.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, TypeAlias + +__all__ = ["Method"] + +Method: TypeAlias = Literal["delete", "get", "head", "options", "patch", "post", "put", "trace"] diff --git a/src/types/namespace.py b/src/types/namespace.py new file mode 100644 index 0000000..a6b6c79 --- /dev/null +++ b/src/types/namespace.py @@ -0,0 +1,9 @@ +# File generated from our OpenAPI spec by Scalar. See README.md for details. + +from __future__ import annotations + +from typing_extensions import TypeAlias + +__all__ = ["Namespace"] + +Namespace: TypeAlias = str diff --git a/src/types/namespace_list_response.py b/src/types/namespace_list_response.py new file mode 100644 index 0000000..6b2ca47 --- /dev/null +++ b/src/types/namespace_list_response.py @@ -0,0 +1,10 @@ +# File generated from our OpenAPI spec by Scalar. See README.md for details. + +from __future__ import annotations + +from typing import List +from typing_extensions import TypeAlias + +__all__ = ["NamespaceListResponse"] + +NamespaceListResponse: TypeAlias = List[str] diff --git a/src/types/nanoid.py b/src/types/nanoid.py new file mode 100644 index 0000000..73e5bac --- /dev/null +++ b/src/types/nanoid.py @@ -0,0 +1,9 @@ +# File generated from our OpenAPI spec by Scalar. See README.md for details. + +from __future__ import annotations + +from typing_extensions import TypeAlias + +__all__ = ["Nanoid"] + +Nanoid: TypeAlias = str diff --git a/src/types/registry_create_api_document_access_group_params.py b/src/types/registry_create_api_document_access_group_params.py new file mode 100644 index 0000000..7be5ced --- /dev/null +++ b/src/types/registry_create_api_document_access_group_params.py @@ -0,0 +1,14 @@ +# File generated from our OpenAPI spec by Scalar. See README.md for details. + +from __future__ import annotations + +from typing import Annotated +from typing_extensions import Required, TypedDict +from .._utils import PropertyInfo + +__all__ = ["RegistryCreateApiDocumentAccessGroupParams"] + + +class RegistryCreateApiDocumentAccessGroupParams(TypedDict, total=False): + + access_group_slug: Required[Annotated[str, PropertyInfo(alias="accessGroupSlug")]] diff --git a/src/types/registry_create_api_document_access_group_response.py b/src/types/registry_create_api_document_access_group_response.py new file mode 100644 index 0000000..7a73e57 --- /dev/null +++ b/src/types/registry_create_api_document_access_group_response.py @@ -0,0 +1,9 @@ +# File generated from our OpenAPI spec by Scalar. See README.md for details. + +from __future__ import annotations + +from typing_extensions import TypeAlias + +__all__ = ["RegistryCreateApiDocumentAccessGroupResponse"] + +RegistryCreateApiDocumentAccessGroupResponse: TypeAlias = None diff --git a/src/types/registry_create_api_document_params.py b/src/types/registry_create_api_document_params.py new file mode 100644 index 0000000..4dedfa6 --- /dev/null +++ b/src/types/registry_create_api_document_params.py @@ -0,0 +1,26 @@ +# File generated from our OpenAPI spec by Scalar. See README.md for details. + +from __future__ import annotations + +from typing import Annotated +from typing_extensions import Required, TypedDict +from .._utils import PropertyInfo + +__all__ = ["RegistryCreateApiDocumentParams"] + + +class RegistryCreateApiDocumentParams(TypedDict, total=False): + + title: Required[str] + + description: str + + version: Required[str] + + slug: Required[str] + + ruleset: str + + is_private: Annotated[bool, PropertyInfo(alias="isPrivate")] + + document: Required[str] diff --git a/src/types/registry_create_api_document_response.py b/src/types/registry_create_api_document_response.py new file mode 100644 index 0000000..e13c4dc --- /dev/null +++ b/src/types/registry_create_api_document_response.py @@ -0,0 +1,9 @@ +# File generated from our OpenAPI spec by Scalar. See README.md for details. + +from __future__ import annotations + +from typing_extensions import TypeAlias + +__all__ = ["RegistryCreateApiDocumentResponse"] + +RegistryCreateApiDocumentResponse: TypeAlias = object diff --git a/src/types/registry_create_api_document_version_params.py b/src/types/registry_create_api_document_version_params.py new file mode 100644 index 0000000..e135774 --- /dev/null +++ b/src/types/registry_create_api_document_version_params.py @@ -0,0 +1,20 @@ +# File generated from our OpenAPI spec by Scalar. See README.md for details. + +from __future__ import annotations + +from typing import Annotated +from typing_extensions import Required, TypedDict +from .._utils import PropertyInfo + +__all__ = ["RegistryCreateApiDocumentVersionParams"] + + +class RegistryCreateApiDocumentVersionParams(TypedDict, total=False): + + version: Required[str] + + document: Required[str] + + force: bool + + last_known_version_sha: Annotated[str, PropertyInfo(alias="lastKnownVersionSha")] diff --git a/src/types/registry_create_api_document_version_response.py b/src/types/registry_create_api_document_version_response.py new file mode 100644 index 0000000..9692d5a --- /dev/null +++ b/src/types/registry_create_api_document_version_response.py @@ -0,0 +1,10 @@ +# File generated from our OpenAPI spec by Scalar. See README.md for details. + +from __future__ import annotations + +from typing_extensions import TypeAlias +from .managed_doc_version import ManagedDocVersion + +__all__ = ["RegistryCreateApiDocumentVersionResponse"] + +RegistryCreateApiDocumentVersionResponse: TypeAlias = ManagedDocVersion diff --git a/src/types/registry_delete_api_document_access_group_params.py b/src/types/registry_delete_api_document_access_group_params.py new file mode 100644 index 0000000..719f324 --- /dev/null +++ b/src/types/registry_delete_api_document_access_group_params.py @@ -0,0 +1,14 @@ +# File generated from our OpenAPI spec by Scalar. See README.md for details. + +from __future__ import annotations + +from typing import Annotated +from typing_extensions import Required, TypedDict +from .._utils import PropertyInfo + +__all__ = ["RegistryDeleteApiDocumentAccessGroupParams"] + + +class RegistryDeleteApiDocumentAccessGroupParams(TypedDict, total=False): + + access_group_slug: Required[Annotated[str, PropertyInfo(alias="accessGroupSlug")]] diff --git a/src/types/registry_delete_api_document_access_group_response.py b/src/types/registry_delete_api_document_access_group_response.py new file mode 100644 index 0000000..ad45c5b --- /dev/null +++ b/src/types/registry_delete_api_document_access_group_response.py @@ -0,0 +1,9 @@ +# File generated from our OpenAPI spec by Scalar. See README.md for details. + +from __future__ import annotations + +from typing_extensions import TypeAlias + +__all__ = ["RegistryDeleteApiDocumentAccessGroupResponse"] + +RegistryDeleteApiDocumentAccessGroupResponse: TypeAlias = None diff --git a/src/types/registry_delete_api_document_response.py b/src/types/registry_delete_api_document_response.py new file mode 100644 index 0000000..c3e26b4 --- /dev/null +++ b/src/types/registry_delete_api_document_response.py @@ -0,0 +1,9 @@ +# File generated from our OpenAPI spec by Scalar. See README.md for details. + +from __future__ import annotations + +from typing_extensions import TypeAlias + +__all__ = ["RegistryDeleteApiDocumentResponse"] + +RegistryDeleteApiDocumentResponse: TypeAlias = None diff --git a/src/types/registry_delete_api_document_version_response.py b/src/types/registry_delete_api_document_version_response.py new file mode 100644 index 0000000..39e1f37 --- /dev/null +++ b/src/types/registry_delete_api_document_version_response.py @@ -0,0 +1,9 @@ +# File generated from our OpenAPI spec by Scalar. See README.md for details. + +from __future__ import annotations + +from typing_extensions import TypeAlias + +__all__ = ["RegistryDeleteApiDocumentVersionResponse"] + +RegistryDeleteApiDocumentVersionResponse: TypeAlias = None diff --git a/src/types/registry_list_all_api_documents_response.py b/src/types/registry_list_all_api_documents_response.py new file mode 100644 index 0000000..9552301 --- /dev/null +++ b/src/types/registry_list_all_api_documents_response.py @@ -0,0 +1,11 @@ +# File generated from our OpenAPI spec by Scalar. See README.md for details. + +from __future__ import annotations + +from typing import List +from typing_extensions import TypeAlias +from .api_document import ApiDocument + +__all__ = ["RegistryListAllApiDocumentsResponse"] + +RegistryListAllApiDocumentsResponse: TypeAlias = List[ApiDocument] diff --git a/src/types/registry_list_api_document_version_metadata_response.py b/src/types/registry_list_api_document_version_metadata_response.py new file mode 100644 index 0000000..0ecf442 --- /dev/null +++ b/src/types/registry_list_api_document_version_metadata_response.py @@ -0,0 +1,10 @@ +# File generated from our OpenAPI spec by Scalar. See README.md for details. + +from __future__ import annotations + +from typing_extensions import TypeAlias +from .managed_doc_version import ManagedDocVersion + +__all__ = ["RegistryListApiDocumentVersionMetadataResponse"] + +RegistryListApiDocumentVersionMetadataResponse: TypeAlias = ManagedDocVersion diff --git a/src/types/registry_list_api_documents_response.py b/src/types/registry_list_api_documents_response.py new file mode 100644 index 0000000..85fbbbf --- /dev/null +++ b/src/types/registry_list_api_documents_response.py @@ -0,0 +1,11 @@ +# File generated from our OpenAPI spec by Scalar. See README.md for details. + +from __future__ import annotations + +from typing import List +from typing_extensions import TypeAlias +from .api_document import ApiDocument + +__all__ = ["RegistryListApiDocumentsResponse"] + +RegistryListApiDocumentsResponse: TypeAlias = List[ApiDocument] diff --git a/src/types/registry_retrieve_api_document_version_response.py b/src/types/registry_retrieve_api_document_version_response.py new file mode 100644 index 0000000..5113289 --- /dev/null +++ b/src/types/registry_retrieve_api_document_version_response.py @@ -0,0 +1,9 @@ +# File generated from our OpenAPI spec by Scalar. See README.md for details. + +from __future__ import annotations + +from typing_extensions import TypeAlias + +__all__ = ["RegistryRetrieveApiDocumentVersionResponse"] + +RegistryRetrieveApiDocumentVersionResponse: TypeAlias = str diff --git a/src/types/registry_update_api_document_params.py b/src/types/registry_update_api_document_params.py new file mode 100644 index 0000000..a48ede5 --- /dev/null +++ b/src/types/registry_update_api_document_params.py @@ -0,0 +1,20 @@ +# File generated from our OpenAPI spec by Scalar. See README.md for details. + +from __future__ import annotations + +from typing import Annotated +from typing_extensions import TypedDict +from .._utils import PropertyInfo + +__all__ = ["RegistryUpdateApiDocumentParams"] + + +class RegistryUpdateApiDocumentParams(TypedDict, total=False): + + title: str + + description: str + + is_private: Annotated[bool, PropertyInfo(alias="isPrivate")] + + ruleset: str diff --git a/src/types/registry_update_api_document_response.py b/src/types/registry_update_api_document_response.py new file mode 100644 index 0000000..5bfd97e --- /dev/null +++ b/src/types/registry_update_api_document_response.py @@ -0,0 +1,9 @@ +# File generated from our OpenAPI spec by Scalar. See README.md for details. + +from __future__ import annotations + +from typing_extensions import TypeAlias + +__all__ = ["RegistryUpdateApiDocumentResponse"] + +RegistryUpdateApiDocumentResponse: TypeAlias = None diff --git a/src/types/registry_update_api_document_version_params.py b/src/types/registry_update_api_document_version_params.py new file mode 100644 index 0000000..b8d3307 --- /dev/null +++ b/src/types/registry_update_api_document_version_params.py @@ -0,0 +1,16 @@ +# File generated from our OpenAPI spec by Scalar. See README.md for details. + +from __future__ import annotations + +from typing import Annotated +from typing_extensions import Required, TypedDict +from .._utils import PropertyInfo + +__all__ = ["RegistryUpdateApiDocumentVersionParams"] + + +class RegistryUpdateApiDocumentVersionParams(TypedDict, total=False): + + document: Required[str] + + last_known_version_sha: Annotated[str, PropertyInfo(alias="lastKnownVersionSha")] diff --git a/src/types/registry_update_api_document_version_response.py b/src/types/registry_update_api_document_version_response.py new file mode 100644 index 0000000..1a39b7a --- /dev/null +++ b/src/types/registry_update_api_document_version_response.py @@ -0,0 +1,9 @@ +# File generated from our OpenAPI spec by Scalar. See README.md for details. + +from __future__ import annotations + +from typing_extensions import TypeAlias + +__all__ = ["RegistryUpdateApiDocumentVersionResponse"] + +RegistryUpdateApiDocumentVersionResponse: TypeAlias = object diff --git a/src/types/rule.py b/src/types/rule.py new file mode 100644 index 0000000..6f4d2fd --- /dev/null +++ b/src/types/rule.py @@ -0,0 +1,24 @@ +# File generated from our OpenAPI spec by Scalar. See README.md for details. + + +from .._models import BaseModel +from .nanoid import Nanoid +from .slug import Slug +from .namespace import Namespace + +__all__ = ["Rule"] + + +class Rule(BaseModel): + + uid: Nanoid + + title: str + + description: str + + slug: Slug + + namespace: Namespace + + isPrivate: bool diff --git a/src/types/rule_create_ruleset_access_group_params.py b/src/types/rule_create_ruleset_access_group_params.py new file mode 100644 index 0000000..08d8023 --- /dev/null +++ b/src/types/rule_create_ruleset_access_group_params.py @@ -0,0 +1,14 @@ +# File generated from our OpenAPI spec by Scalar. See README.md for details. + +from __future__ import annotations + +from typing import Annotated +from typing_extensions import Required, TypedDict +from .._utils import PropertyInfo + +__all__ = ["RuleCreateRulesetAccessGroupParams"] + + +class RuleCreateRulesetAccessGroupParams(TypedDict, total=False): + + access_group_slug: Required[Annotated[str, PropertyInfo(alias="accessGroupSlug")]] diff --git a/src/types/rule_create_ruleset_access_group_response.py b/src/types/rule_create_ruleset_access_group_response.py new file mode 100644 index 0000000..2a60e6f --- /dev/null +++ b/src/types/rule_create_ruleset_access_group_response.py @@ -0,0 +1,9 @@ +# File generated from our OpenAPI spec by Scalar. See README.md for details. + +from __future__ import annotations + +from typing_extensions import TypeAlias + +__all__ = ["RuleCreateRulesetAccessGroupResponse"] + +RuleCreateRulesetAccessGroupResponse: TypeAlias = None diff --git a/src/types/rule_create_ruleset_params.py b/src/types/rule_create_ruleset_params.py new file mode 100644 index 0000000..7e70c5a --- /dev/null +++ b/src/types/rule_create_ruleset_params.py @@ -0,0 +1,22 @@ +# File generated from our OpenAPI spec by Scalar. See README.md for details. + +from __future__ import annotations + +from typing import Annotated +from typing_extensions import Required, TypedDict +from .._utils import PropertyInfo + +__all__ = ["RuleCreateRulesetParams"] + + +class RuleCreateRulesetParams(TypedDict, total=False): + + title: Required[str] + + description: str + + slug: Required[str] + + is_private: Annotated[bool, PropertyInfo(alias="isPrivate")] + + document: Required[str] diff --git a/src/types/rule_create_ruleset_response.py b/src/types/rule_create_ruleset_response.py new file mode 100644 index 0000000..d829ec3 --- /dev/null +++ b/src/types/rule_create_ruleset_response.py @@ -0,0 +1,10 @@ +# File generated from our OpenAPI spec by Scalar. See README.md for details. + +from __future__ import annotations + +from typing_extensions import TypeAlias +from .uid import Uid + +__all__ = ["RuleCreateRulesetResponse"] + +RuleCreateRulesetResponse: TypeAlias = Uid diff --git a/src/types/rule_delete_ruleset_access_group_params.py b/src/types/rule_delete_ruleset_access_group_params.py new file mode 100644 index 0000000..502f63c --- /dev/null +++ b/src/types/rule_delete_ruleset_access_group_params.py @@ -0,0 +1,14 @@ +# File generated from our OpenAPI spec by Scalar. See README.md for details. + +from __future__ import annotations + +from typing import Annotated +from typing_extensions import Required, TypedDict +from .._utils import PropertyInfo + +__all__ = ["RuleDeleteRulesetAccessGroupParams"] + + +class RuleDeleteRulesetAccessGroupParams(TypedDict, total=False): + + access_group_slug: Required[Annotated[str, PropertyInfo(alias="accessGroupSlug")]] diff --git a/src/types/rule_delete_ruleset_access_group_response.py b/src/types/rule_delete_ruleset_access_group_response.py new file mode 100644 index 0000000..8e6814f --- /dev/null +++ b/src/types/rule_delete_ruleset_access_group_response.py @@ -0,0 +1,9 @@ +# File generated from our OpenAPI spec by Scalar. See README.md for details. + +from __future__ import annotations + +from typing_extensions import TypeAlias + +__all__ = ["RuleDeleteRulesetAccessGroupResponse"] + +RuleDeleteRulesetAccessGroupResponse: TypeAlias = None diff --git a/src/types/rule_delete_ruleset_response.py b/src/types/rule_delete_ruleset_response.py new file mode 100644 index 0000000..0f7eacd --- /dev/null +++ b/src/types/rule_delete_ruleset_response.py @@ -0,0 +1,9 @@ +# File generated from our OpenAPI spec by Scalar. See README.md for details. + +from __future__ import annotations + +from typing_extensions import TypeAlias + +__all__ = ["RuleDeleteRulesetResponse"] + +RuleDeleteRulesetResponse: TypeAlias = None diff --git a/src/types/rule_list_rulesets_response.py b/src/types/rule_list_rulesets_response.py new file mode 100644 index 0000000..0ab5bac --- /dev/null +++ b/src/types/rule_list_rulesets_response.py @@ -0,0 +1,11 @@ +# File generated from our OpenAPI spec by Scalar. See README.md for details. + +from __future__ import annotations + +from typing import List +from typing_extensions import TypeAlias +from .rule import Rule + +__all__ = ["RuleListRulesetsResponse"] + +RuleListRulesetsResponse: TypeAlias = List[Rule] diff --git a/src/types/rule_retrieve_ruleset_document_response.py b/src/types/rule_retrieve_ruleset_document_response.py new file mode 100644 index 0000000..14fa017 --- /dev/null +++ b/src/types/rule_retrieve_ruleset_document_response.py @@ -0,0 +1,9 @@ +# File generated from our OpenAPI spec by Scalar. See README.md for details. + +from __future__ import annotations + +from typing_extensions import TypeAlias + +__all__ = ["RuleRetrieveRulesetDocumentResponse"] + +RuleRetrieveRulesetDocumentResponse: TypeAlias = str diff --git a/src/types/rule_update_ruleset_params.py b/src/types/rule_update_ruleset_params.py new file mode 100644 index 0000000..41b3811 --- /dev/null +++ b/src/types/rule_update_ruleset_params.py @@ -0,0 +1,22 @@ +# File generated from our OpenAPI spec by Scalar. See README.md for details. + +from __future__ import annotations + +from typing import Annotated +from typing_extensions import TypedDict +from .._utils import PropertyInfo + +__all__ = ["RuleUpdateRulesetParams"] + + +class RuleUpdateRulesetParams(TypedDict, total=False): + + namespace: str + + slug: str + + title: str + + description: str + + is_private: Annotated[bool, PropertyInfo(alias="isPrivate")] diff --git a/src/types/rule_update_ruleset_response.py b/src/types/rule_update_ruleset_response.py new file mode 100644 index 0000000..1b2a74d --- /dev/null +++ b/src/types/rule_update_ruleset_response.py @@ -0,0 +1,9 @@ +# File generated from our OpenAPI spec by Scalar. See README.md for details. + +from __future__ import annotations + +from typing_extensions import TypeAlias + +__all__ = ["RuleUpdateRulesetResponse"] + +RuleUpdateRulesetResponse: TypeAlias = None diff --git a/src/types/scalar_doc_create_guide_params.py b/src/types/scalar_doc_create_guide_params.py new file mode 100644 index 0000000..38ca7e5 --- /dev/null +++ b/src/types/scalar_doc_create_guide_params.py @@ -0,0 +1,22 @@ +# File generated from our OpenAPI spec by Scalar. See README.md for details. + +from __future__ import annotations + +from typing import Annotated, List +from typing_extensions import Required, TypedDict +from .._utils import PropertyInfo + +__all__ = ["ScalarDocCreateGuideParams"] + + +class ScalarDocCreateGuideParams(TypedDict, total=False): + + name: Required[str] + + slug: str + + is_private: Required[Annotated[bool, PropertyInfo(alias="isPrivate")]] + + allowed_users: Required[Annotated[List[str], PropertyInfo(alias="allowedUsers")]] + + allowed_domains: Required[Annotated[List[str], PropertyInfo(alias="allowedDomains")]] diff --git a/src/types/scalar_doc_create_guide_response.py b/src/types/scalar_doc_create_guide_response.py new file mode 100644 index 0000000..4899376 --- /dev/null +++ b/src/types/scalar_doc_create_guide_response.py @@ -0,0 +1,9 @@ +# File generated from our OpenAPI spec by Scalar. See README.md for details. + +from __future__ import annotations + +from typing_extensions import TypeAlias + +__all__ = ["ScalarDocCreateGuideResponse"] + +ScalarDocCreateGuideResponse: TypeAlias = object diff --git a/src/types/scalar_doc_list_guides_response.py b/src/types/scalar_doc_list_guides_response.py new file mode 100644 index 0000000..82e4197 --- /dev/null +++ b/src/types/scalar_doc_list_guides_response.py @@ -0,0 +1,11 @@ +# File generated from our OpenAPI spec by Scalar. See README.md for details. + +from __future__ import annotations + +from typing import List +from typing_extensions import TypeAlias +from .github_project import GithubProject + +__all__ = ["ScalarDocListGuidesResponse"] + +ScalarDocListGuidesResponse: TypeAlias = List[GithubProject] diff --git a/src/types/scalar_doc_publish_guide_response.py b/src/types/scalar_doc_publish_guide_response.py new file mode 100644 index 0000000..1befb57 --- /dev/null +++ b/src/types/scalar_doc_publish_guide_response.py @@ -0,0 +1,9 @@ +# File generated from our OpenAPI spec by Scalar. See README.md for details. + +from __future__ import annotations + +from typing_extensions import TypeAlias + +__all__ = ["ScalarDocPublishGuideResponse"] + +ScalarDocPublishGuideResponse: TypeAlias = object diff --git a/src/types/schema.py b/src/types/schema.py new file mode 100644 index 0000000..fc9ca8e --- /dev/null +++ b/src/types/schema.py @@ -0,0 +1,28 @@ +# File generated from our OpenAPI spec by Scalar. See README.md for details. + +from typing import List + +from .._models import BaseModel +from .nanoid import Nanoid +from .slug import Slug +from .namespace import Namespace +from .managed_schema_version import ManagedSchemaVersion + +__all__ = ["Schema"] + + +class Schema(BaseModel): + + uid: Nanoid + + title: str + + description: str + + slug: Slug + + namespace: Namespace + + isPrivate: bool + + versions: List[ManagedSchemaVersion] diff --git a/src/types/schema_create_params.py b/src/types/schema_create_params.py new file mode 100644 index 0000000..dc95811 --- /dev/null +++ b/src/types/schema_create_params.py @@ -0,0 +1,24 @@ +# File generated from our OpenAPI spec by Scalar. See README.md for details. + +from __future__ import annotations + +from typing import Annotated +from typing_extensions import Required, TypedDict +from .._utils import PropertyInfo + +__all__ = ["SchemaCreateParams"] + + +class SchemaCreateParams(TypedDict, total=False): + + title: Required[str] + + description: str + + version: Required[str] + + slug: Required[str] + + is_private: Annotated[bool, PropertyInfo(alias="isPrivate")] + + document: Required[str] diff --git a/src/types/schema_create_response.py b/src/types/schema_create_response.py new file mode 100644 index 0000000..8e7792a --- /dev/null +++ b/src/types/schema_create_response.py @@ -0,0 +1,10 @@ +# File generated from our OpenAPI spec by Scalar. See README.md for details. + +from __future__ import annotations + +from typing_extensions import TypeAlias +from .uid import Uid + +__all__ = ["SchemaCreateResponse"] + +SchemaCreateResponse: TypeAlias = Uid diff --git a/src/types/schema_delete_response.py b/src/types/schema_delete_response.py new file mode 100644 index 0000000..d1b662b --- /dev/null +++ b/src/types/schema_delete_response.py @@ -0,0 +1,9 @@ +# File generated from our OpenAPI spec by Scalar. See README.md for details. + +from __future__ import annotations + +from typing_extensions import TypeAlias + +__all__ = ["SchemaDeleteResponse"] + +SchemaDeleteResponse: TypeAlias = None diff --git a/src/types/schema_list_response.py b/src/types/schema_list_response.py new file mode 100644 index 0000000..93ca662 --- /dev/null +++ b/src/types/schema_list_response.py @@ -0,0 +1,11 @@ +# File generated from our OpenAPI spec by Scalar. See README.md for details. + +from __future__ import annotations + +from typing import List +from typing_extensions import TypeAlias +from .schema import Schema + +__all__ = ["SchemaListResponse"] + +SchemaListResponse: TypeAlias = List[Schema] diff --git a/src/types/schema_update_params.py b/src/types/schema_update_params.py new file mode 100644 index 0000000..e4bac0f --- /dev/null +++ b/src/types/schema_update_params.py @@ -0,0 +1,18 @@ +# File generated from our OpenAPI spec by Scalar. See README.md for details. + +from __future__ import annotations + +from typing import Annotated +from typing_extensions import TypedDict +from .._utils import PropertyInfo + +__all__ = ["SchemaUpdateParams"] + + +class SchemaUpdateParams(TypedDict, total=False): + + title: str + + description: str + + is_private: Annotated[bool, PropertyInfo(alias="isPrivate")] diff --git a/src/types/schema_update_response.py b/src/types/schema_update_response.py new file mode 100644 index 0000000..8d20eeb --- /dev/null +++ b/src/types/schema_update_response.py @@ -0,0 +1,9 @@ +# File generated from our OpenAPI spec by Scalar. See README.md for details. + +from __future__ import annotations + +from typing_extensions import TypeAlias + +__all__ = ["SchemaUpdateResponse"] + +SchemaUpdateResponse: TypeAlias = None diff --git a/src/types/schemas/__init__.py b/src/types/schemas/__init__.py new file mode 100644 index 0000000..640f96a --- /dev/null +++ b/src/types/schemas/__init__.py @@ -0,0 +1,12 @@ +# File generated from our OpenAPI spec by Scalar. See README.md for details. + +from __future__ import annotations + +from .version_retrieve_schema_response import VersionRetrieveSchemaResponse as VersionRetrieveSchemaResponse +from .version_delete_schema_response import VersionDeleteSchemaResponse as VersionDeleteSchemaResponse +from .version_create_schema_response import VersionCreateSchemaResponse as VersionCreateSchemaResponse +from .version_create_schema_params import VersionCreateSchemaParams as VersionCreateSchemaParams +from .access_group_create_schema_response import AccessGroupCreateSchemaResponse as AccessGroupCreateSchemaResponse +from .access_group_create_schema_params import AccessGroupCreateSchemaParams as AccessGroupCreateSchemaParams +from .access_group_delete_schema_response import AccessGroupDeleteSchemaResponse as AccessGroupDeleteSchemaResponse +from .access_group_delete_schema_params import AccessGroupDeleteSchemaParams as AccessGroupDeleteSchemaParams diff --git a/src/types/schemas/access_group_create_schema_params.py b/src/types/schemas/access_group_create_schema_params.py new file mode 100644 index 0000000..034b841 --- /dev/null +++ b/src/types/schemas/access_group_create_schema_params.py @@ -0,0 +1,14 @@ +# File generated from our OpenAPI spec by Scalar. See README.md for details. + +from __future__ import annotations + +from typing import Annotated +from typing_extensions import Required, TypedDict +from ..._utils import PropertyInfo + +__all__ = ["AccessGroupCreateSchemaParams"] + + +class AccessGroupCreateSchemaParams(TypedDict, total=False): + + access_group_slug: Required[Annotated[str, PropertyInfo(alias="accessGroupSlug")]] diff --git a/src/types/schemas/access_group_create_schema_response.py b/src/types/schemas/access_group_create_schema_response.py new file mode 100644 index 0000000..4a7bbc5 --- /dev/null +++ b/src/types/schemas/access_group_create_schema_response.py @@ -0,0 +1,9 @@ +# File generated from our OpenAPI spec by Scalar. See README.md for details. + +from __future__ import annotations + +from typing_extensions import TypeAlias + +__all__ = ["AccessGroupCreateSchemaResponse"] + +AccessGroupCreateSchemaResponse: TypeAlias = None diff --git a/src/types/schemas/access_group_delete_schema_params.py b/src/types/schemas/access_group_delete_schema_params.py new file mode 100644 index 0000000..c17eb49 --- /dev/null +++ b/src/types/schemas/access_group_delete_schema_params.py @@ -0,0 +1,14 @@ +# File generated from our OpenAPI spec by Scalar. See README.md for details. + +from __future__ import annotations + +from typing import Annotated +from typing_extensions import Required, TypedDict +from ..._utils import PropertyInfo + +__all__ = ["AccessGroupDeleteSchemaParams"] + + +class AccessGroupDeleteSchemaParams(TypedDict, total=False): + + access_group_slug: Required[Annotated[str, PropertyInfo(alias="accessGroupSlug")]] diff --git a/src/types/schemas/access_group_delete_schema_response.py b/src/types/schemas/access_group_delete_schema_response.py new file mode 100644 index 0000000..2f95a9f --- /dev/null +++ b/src/types/schemas/access_group_delete_schema_response.py @@ -0,0 +1,9 @@ +# File generated from our OpenAPI spec by Scalar. See README.md for details. + +from __future__ import annotations + +from typing_extensions import TypeAlias + +__all__ = ["AccessGroupDeleteSchemaResponse"] + +AccessGroupDeleteSchemaResponse: TypeAlias = None diff --git a/src/types/schemas/version_create_schema_params.py b/src/types/schemas/version_create_schema_params.py new file mode 100644 index 0000000..95a659e --- /dev/null +++ b/src/types/schemas/version_create_schema_params.py @@ -0,0 +1,14 @@ +# File generated from our OpenAPI spec by Scalar. See README.md for details. + +from __future__ import annotations + +from typing_extensions import Required, TypedDict + +__all__ = ["VersionCreateSchemaParams"] + + +class VersionCreateSchemaParams(TypedDict, total=False): + + version: Required[str] + + document: Required[str] diff --git a/src/types/schemas/version_create_schema_response.py b/src/types/schemas/version_create_schema_response.py new file mode 100644 index 0000000..88e7d40 --- /dev/null +++ b/src/types/schemas/version_create_schema_response.py @@ -0,0 +1,10 @@ +# File generated from our OpenAPI spec by Scalar. See README.md for details. + +from __future__ import annotations + +from typing_extensions import TypeAlias +from ..uid import Uid + +__all__ = ["VersionCreateSchemaResponse"] + +VersionCreateSchemaResponse: TypeAlias = Uid diff --git a/src/types/schemas/version_delete_schema_response.py b/src/types/schemas/version_delete_schema_response.py new file mode 100644 index 0000000..25078d4 --- /dev/null +++ b/src/types/schemas/version_delete_schema_response.py @@ -0,0 +1,9 @@ +# File generated from our OpenAPI spec by Scalar. See README.md for details. + +from __future__ import annotations + +from typing_extensions import TypeAlias + +__all__ = ["VersionDeleteSchemaResponse"] + +VersionDeleteSchemaResponse: TypeAlias = None diff --git a/src/types/schemas/version_retrieve_schema_response.py b/src/types/schemas/version_retrieve_schema_response.py new file mode 100644 index 0000000..154cea5 --- /dev/null +++ b/src/types/schemas/version_retrieve_schema_response.py @@ -0,0 +1,9 @@ +# File generated from our OpenAPI spec by Scalar. See README.md for details. + +from __future__ import annotations + +from typing_extensions import TypeAlias + +__all__ = ["VersionRetrieveSchemaResponse"] + +VersionRetrieveSchemaResponse: TypeAlias = str diff --git a/src/types/slug.py b/src/types/slug.py new file mode 100644 index 0000000..3925e4d --- /dev/null +++ b/src/types/slug.py @@ -0,0 +1,9 @@ +# File generated from our OpenAPI spec by Scalar. See README.md for details. + +from __future__ import annotations + +from typing_extensions import TypeAlias + +__all__ = ["Slug"] + +Slug: TypeAlias = str diff --git a/src/types/team.py b/src/types/team.py new file mode 100644 index 0000000..cd07803 --- /dev/null +++ b/src/types/team.py @@ -0,0 +1,24 @@ +# File generated from our OpenAPI spec by Scalar. See README.md for details. + +from typing import Optional + +from .._models import BaseModel +from .nanoid import Nanoid +from .team_name import TeamName +from .team_image import TeamImage +from .slug import Slug + +__all__ = ["Team"] + + +class Team(BaseModel): + + uid: Nanoid + + name: TeamName + + imageUri: Optional[TeamImage] = None + + slug: Slug + + theme: str diff --git a/src/types/team_image.py b/src/types/team_image.py new file mode 100644 index 0000000..5d2e625 --- /dev/null +++ b/src/types/team_image.py @@ -0,0 +1,9 @@ +# File generated from our OpenAPI spec by Scalar. See README.md for details. + +from __future__ import annotations + +from typing_extensions import TypeAlias + +__all__ = ["TeamImage"] + +TeamImage: TypeAlias = str diff --git a/src/types/team_list_response.py b/src/types/team_list_response.py new file mode 100644 index 0000000..39698a7 --- /dev/null +++ b/src/types/team_list_response.py @@ -0,0 +1,11 @@ +# File generated from our OpenAPI spec by Scalar. See README.md for details. + +from __future__ import annotations + +from typing import List +from typing_extensions import TypeAlias +from .team import Team + +__all__ = ["TeamListResponse"] + +TeamListResponse: TypeAlias = List[Team] diff --git a/src/types/team_name.py b/src/types/team_name.py new file mode 100644 index 0000000..2bf4ed8 --- /dev/null +++ b/src/types/team_name.py @@ -0,0 +1,9 @@ +# File generated from our OpenAPI spec by Scalar. See README.md for details. + +from __future__ import annotations + +from typing_extensions import TypeAlias + +__all__ = ["TeamName"] + +TeamName: TypeAlias = str diff --git a/src/types/team_summary.py b/src/types/team_summary.py new file mode 100644 index 0000000..bc4d716 --- /dev/null +++ b/src/types/team_summary.py @@ -0,0 +1,19 @@ +# File generated from our OpenAPI spec by Scalar. See README.md for details. + +from typing import Optional + +from .._models import BaseModel +from .nanoid import Nanoid +from .team_name import TeamName +from .team_image import TeamImage + +__all__ = ["TeamSummary"] + + +class TeamSummary(BaseModel): + + uid: Nanoid + + name: TeamName + + imageUri: Optional[TeamImage] = None diff --git a/src/types/theme.py b/src/types/theme.py new file mode 100644 index 0000000..24ba21d --- /dev/null +++ b/src/types/theme.py @@ -0,0 +1,19 @@ +# File generated from our OpenAPI spec by Scalar. See README.md for details. + + +from .._models import BaseModel +from .nanoid import Nanoid +from .slug import Slug + +__all__ = ["Theme"] + + +class Theme(BaseModel): + + uid: Nanoid + + name: str + + description: str + + slug: Slug diff --git a/src/types/theme_create_params.py b/src/types/theme_create_params.py new file mode 100644 index 0000000..9e1c513 --- /dev/null +++ b/src/types/theme_create_params.py @@ -0,0 +1,18 @@ +# File generated from our OpenAPI spec by Scalar. See README.md for details. + +from __future__ import annotations + +from typing_extensions import Required, TypedDict + +__all__ = ["ThemeCreateParams"] + + +class ThemeCreateParams(TypedDict, total=False): + + name: Required[str] + + description: str + + slug: Required[str] + + document: Required[str] diff --git a/src/types/theme_create_response.py b/src/types/theme_create_response.py new file mode 100644 index 0000000..fd27bad --- /dev/null +++ b/src/types/theme_create_response.py @@ -0,0 +1,10 @@ +# File generated from our OpenAPI spec by Scalar. See README.md for details. + +from __future__ import annotations + +from typing_extensions import TypeAlias +from .uid import Uid + +__all__ = ["ThemeCreateResponse"] + +ThemeCreateResponse: TypeAlias = Uid diff --git a/src/types/theme_delete_response.py b/src/types/theme_delete_response.py new file mode 100644 index 0000000..87e53d2 --- /dev/null +++ b/src/types/theme_delete_response.py @@ -0,0 +1,9 @@ +# File generated from our OpenAPI spec by Scalar. See README.md for details. + +from __future__ import annotations + +from typing_extensions import TypeAlias + +__all__ = ["ThemeDeleteResponse"] + +ThemeDeleteResponse: TypeAlias = None diff --git a/src/types/theme_list_response.py b/src/types/theme_list_response.py new file mode 100644 index 0000000..7f5b941 --- /dev/null +++ b/src/types/theme_list_response.py @@ -0,0 +1,11 @@ +# File generated from our OpenAPI spec by Scalar. See README.md for details. + +from __future__ import annotations + +from typing import List +from typing_extensions import TypeAlias +from .theme import Theme + +__all__ = ["ThemeListResponse"] + +ThemeListResponse: TypeAlias = List[Theme] diff --git a/src/types/theme_replace_document_params.py b/src/types/theme_replace_document_params.py new file mode 100644 index 0000000..8f41750 --- /dev/null +++ b/src/types/theme_replace_document_params.py @@ -0,0 +1,12 @@ +# File generated from our OpenAPI spec by Scalar. See README.md for details. + +from __future__ import annotations + +from typing_extensions import Required, TypedDict + +__all__ = ["ThemeReplaceDocumentParams"] + + +class ThemeReplaceDocumentParams(TypedDict, total=False): + + document: Required[str] diff --git a/src/types/theme_replace_document_response.py b/src/types/theme_replace_document_response.py new file mode 100644 index 0000000..26395b2 --- /dev/null +++ b/src/types/theme_replace_document_response.py @@ -0,0 +1,9 @@ +# File generated from our OpenAPI spec by Scalar. See README.md for details. + +from __future__ import annotations + +from typing_extensions import TypeAlias + +__all__ = ["ThemeReplaceDocumentResponse"] + +ThemeReplaceDocumentResponse: TypeAlias = None diff --git a/src/types/theme_retrieve_response.py b/src/types/theme_retrieve_response.py new file mode 100644 index 0000000..c4af558 --- /dev/null +++ b/src/types/theme_retrieve_response.py @@ -0,0 +1,9 @@ +# File generated from our OpenAPI spec by Scalar. See README.md for details. + +from __future__ import annotations + +from typing_extensions import TypeAlias + +__all__ = ["ThemeRetrieveResponse"] + +ThemeRetrieveResponse: TypeAlias = str diff --git a/src/types/theme_update_params.py b/src/types/theme_update_params.py new file mode 100644 index 0000000..d7b438b --- /dev/null +++ b/src/types/theme_update_params.py @@ -0,0 +1,14 @@ +# File generated from our OpenAPI spec by Scalar. See README.md for details. + +from __future__ import annotations + +from typing_extensions import TypedDict + +__all__ = ["ThemeUpdateParams"] + + +class ThemeUpdateParams(TypedDict, total=False): + + name: str + + description: str diff --git a/src/types/theme_update_response.py b/src/types/theme_update_response.py new file mode 100644 index 0000000..bde2d8e --- /dev/null +++ b/src/types/theme_update_response.py @@ -0,0 +1,9 @@ +# File generated from our OpenAPI spec by Scalar. See README.md for details. + +from __future__ import annotations + +from typing_extensions import TypeAlias + +__all__ = ["ThemeUpdateResponse"] + +ThemeUpdateResponse: TypeAlias = None diff --git a/src/types/timestamp.py b/src/types/timestamp.py new file mode 100644 index 0000000..1185561 --- /dev/null +++ b/src/types/timestamp.py @@ -0,0 +1,9 @@ +# File generated from our OpenAPI spec by Scalar. See README.md for details. + +from __future__ import annotations + +from typing_extensions import TypeAlias + +__all__ = ["Timestamp"] + +Timestamp: TypeAlias = int diff --git a/src/types/uid.py b/src/types/uid.py new file mode 100644 index 0000000..2be173b --- /dev/null +++ b/src/types/uid.py @@ -0,0 +1,12 @@ +# File generated from our OpenAPI spec by Scalar. See README.md for details. + + +from .._models import BaseModel +from .nanoid import Nanoid + +__all__ = ["Uid"] + + +class Uid(BaseModel): + + uid: Nanoid diff --git a/src/types/user.py b/src/types/user.py new file mode 100644 index 0000000..ab9c228 --- /dev/null +++ b/src/types/user.py @@ -0,0 +1,30 @@ +# File generated from our OpenAPI spec by Scalar. See README.md for details. + +from typing import List, Optional, Union + +from .._models import BaseModel +from .nanoid import Nanoid +from .timestamp import Timestamp +from .email import Email +from .team_summary import TeamSummary + +__all__ = ["User"] + + +class User(BaseModel): + + uid: Nanoid + + createdAt: Timestamp + + updatedAt: Timestamp + + email: Email + + theme: Optional[str] = None + + activeTeamId: Optional[Union[str, None]] = None + + hasGithub: bool + + teams: List[TeamSummary] diff --git a/src/types/version.py b/src/types/version.py new file mode 100644 index 0000000..d8c8fff --- /dev/null +++ b/src/types/version.py @@ -0,0 +1,9 @@ +# File generated from our OpenAPI spec by Scalar. See README.md for details. + +from __future__ import annotations + +from typing_extensions import TypeAlias + +__all__ = ["Version"] + +Version: TypeAlias = str diff --git a/tests/smoke-test.py b/tests/smoke-test.py new file mode 100644 index 0000000..13c74d1 --- /dev/null +++ b/tests/smoke-test.py @@ -0,0 +1,732 @@ +# File generated from our OpenAPI spec by Scalar. See README.md for details. + +# Smoke test: calls every generated operation once to confirm the SDK can reach each endpoint. +# Run it from this repo with `python tests/smoke-test.py`. The generator also runs this file +# against a mock server and reads the JSON report produced via SCALAR_SMOKE_REPORT. +from __future__ import annotations + +import json +import os +import sys +import time +import traceback +from concurrent.futures import ThreadPoolExecutor +from pathlib import Path +from typing import Any, Callable, TypedDict + +from scalar_api import ScalarApi + +# The shared smoke-test runner injects base URL and credentials through the same +# environment variables the generated client reads in normal use. +client = ScalarApi(max_retries=0, timeout=30) + + +class SmokeResult(TypedDict, total=False): + operation: str + method: str + path: str + status: str + durationMs: int + error: str + + +class SmokeCase(TypedDict): + operation: str + method: str + path: str + run: Callable[[], Any] + + +def _smoke_case_0() -> None: + registry = client.registry.list_all_api_documents() + +def _smoke_case_1() -> None: + registry = client.registry.list_api_documents( + namespace="namespace", + ) + +def _smoke_case_2() -> None: + registry = client.registry.create_api_document( + namespace="namespace", + title="", + version="", + slug="", + document="", + idempotency_key="", + ) + +def _smoke_case_3() -> None: + registry = client.registry.update_api_document( + namespace="namespace", + slug="slug", + idempotency_key="", + ) + +def _smoke_case_4() -> None: + registry = client.registry.delete_api_document( + namespace="namespace", + slug="slug", + idempotency_key="", + ) + +def _smoke_case_5() -> None: + registry = client.registry.retrieve_api_document_version( + namespace="namespace", + slug="slug", + semver="semver", + ) + +def _smoke_case_6() -> None: + registry = client.registry.update_api_document_version( + namespace="namespace", + slug="slug", + semver="semver", + document="", + idempotency_key="", + ) + +def _smoke_case_7() -> None: + registry = client.registry.delete_api_document_version( + namespace="namespace", + slug="slug", + semver="semver", + idempotency_key="", + ) + +def _smoke_case_8() -> None: + registry = client.registry.list_api_document_version_metadata( + namespace="namespace", + slug="slug", + semver="semver", + ) + +def _smoke_case_9() -> None: + registry = client.registry.create_api_document_version( + namespace="namespace", + slug="slug", + version="", + document="", + idempotency_key="", + ) + +def _smoke_case_10() -> None: + registry = client.registry.create_api_document_access_group( + namespace="namespace", + slug="slug", + access_group_slug="", + idempotency_key="", + ) + +def _smoke_case_11() -> None: + registry = client.registry.delete_api_document_access_group( + namespace="namespace", + slug="slug", + access_group_slug="", + idempotency_key="", + ) + +def _smoke_case_12() -> None: + schema = client.schemas.list( + namespace="namespace", + ) + +def _smoke_case_13() -> None: + schema = client.schemas.create( + namespace="namespace", + title="", + version="", + slug="", + document="", + idempotency_key="", + ) + +def _smoke_case_14() -> None: + schema = client.schemas.update( + namespace="namespace", + slug="slug", + idempotency_key="", + ) + +def _smoke_case_15() -> None: + schema = client.schemas.delete( + namespace="namespace", + slug="slug", + idempotency_key="", + ) + +def _smoke_case_16() -> None: + version = client.schemas.version.retrieve_schema( + namespace="namespace", + slug="slug", + semver="semver", + ) + +def _smoke_case_17() -> None: + version = client.schemas.version.delete_schema( + namespace="namespace", + slug="slug", + semver="semver", + idempotency_key="", + ) + +def _smoke_case_18() -> None: + version = client.schemas.version.create_schema( + namespace="namespace", + slug="slug", + version="", + document="", + idempotency_key="", + ) + +def _smoke_case_19() -> None: + access_group = client.schemas.access_group.create_schema( + namespace="namespace", + slug="slug", + access_group_slug="", + idempotency_key="", + ) + +def _smoke_case_20() -> None: + access_group = client.schemas.access_group.delete_schema( + namespace="namespace", + slug="slug", + access_group_slug="", + idempotency_key="", + ) + +def _smoke_case_21() -> None: + login_portal = client.login_portals.retrieve( + slug="slug", + ) + +def _smoke_case_22() -> None: + login_portal = client.login_portals.update( + slug="slug", + idempotency_key="", + ) + +def _smoke_case_23() -> None: + login_portal = client.login_portals.delete( + slug="slug", + idempotency_key="", + ) + +def _smoke_case_24() -> None: + login_portal = client.login_portals.create( + title="", + slug="", + email={"logo": "", "logo_size": "100", "button_text": "Login", "message": "Click to access private documentation hosted by scalar.com", "title": "Private Docs", "main_color": "#2a2f45", "main_background": "#f6f6f6", "card_color": "2a2f45", "card_background": "#fff", "button_color": "#fff", "button_background": "#0f0f0f"}, + page={"title": "Scalar Private Docs", "description": "Login to access your documentation", "head": "", "script": "", "theme": "", "company_name": "", "logo": "", "logo_url": "", "favicon": "", "terms_link": "", "privacy_link": "", "form_title": "Scalar Private Docs", "form_description": "Login to access your documentation", "form_image": ""}, + idempotency_key="", + ) + +def _smoke_case_25() -> None: + login_portal = client.login_portals.list() + +def _smoke_case_26() -> None: + rule = client.rules.list_rulesets( + namespace="namespace", + ) + +def _smoke_case_27() -> None: + rule = client.rules.create_ruleset( + namespace="namespace", + title="", + slug="", + document="", + idempotency_key="", + ) + +def _smoke_case_28() -> None: + rule = client.rules.update_ruleset( + namespace="namespace", + slug="slug", + idempotency_key="", + ) + +def _smoke_case_29() -> None: + rule = client.rules.delete_ruleset( + namespace="namespace", + slug="slug", + idempotency_key="", + ) + +def _smoke_case_30() -> None: + rule = client.rules.retrieve_ruleset_document( + namespace="namespace", + slug="slug", + ) + +def _smoke_case_31() -> None: + rule = client.rules.create_ruleset_access_group( + namespace="namespace", + slug="slug", + access_group_slug="", + idempotency_key="", + ) + +def _smoke_case_32() -> None: + rule = client.rules.delete_ruleset_access_group( + namespace="namespace", + slug="slug", + access_group_slug="", + idempotency_key="", + ) + +def _smoke_case_33() -> None: + theme = client.themes.list() + +def _smoke_case_34() -> None: + theme = client.themes.create( + name="", + slug="", + document="", + idempotency_key="", + ) + +def _smoke_case_35() -> None: + theme = client.themes.update( + slug="slug", + idempotency_key="", + ) + +def _smoke_case_36() -> None: + theme = client.themes.replace_document( + slug="slug", + document="", + idempotency_key="", + ) + +def _smoke_case_37() -> None: + theme = client.themes.delete( + slug="slug", + idempotency_key="", + ) + +def _smoke_case_38() -> None: + theme = client.themes.retrieve( + slug="slug", + ) + +def _smoke_case_39() -> None: + team = client.teams.list() + +def _smoke_case_40() -> None: + scalar_doc = client.scalar_docs.list_guides() + +def _smoke_case_41() -> None: + scalar_doc = client.scalar_docs.create_guide( + name="", + is_private=False, + allowed_users=[], + allowed_domains=[], + idempotency_key="", + ) + +def _smoke_case_42() -> None: + scalar_doc = client.scalar_docs.publish_guide( + slug="slug", + idempotency_key="", + ) + +def _smoke_case_43() -> None: + namespace = client.namespaces.list() + +def _smoke_case_44() -> None: + authentication = client.authentication.exchange_personal_token( + personal_token="", + idempotency_key="", + ) + +def _smoke_case_45() -> None: + authentication = client.authentication.list_current_user() + + +cases: list[SmokeCase] = [ + { + "operation": "listAllApiDocuments", + "method": "GET", + "path": "/v1/apis", + "run": _smoke_case_0, + }, + + { + "operation": "listApiDocuments", + "method": "GET", + "path": "/v1/apis/{namespace}", + "run": _smoke_case_1, + }, + + { + "operation": "createApiDocument", + "method": "POST", + "path": "/v1/apis/{namespace}", + "run": _smoke_case_2, + }, + + { + "operation": "updateApiDocument", + "method": "PATCH", + "path": "/v1/apis/{namespace}/{slug}", + "run": _smoke_case_3, + }, + + { + "operation": "deleteApiDocument", + "method": "DELETE", + "path": "/v1/apis/{namespace}/{slug}", + "run": _smoke_case_4, + }, + + { + "operation": "retrieveApiDocumentVersion", + "method": "GET", + "path": "/v1/apis/{namespace}/{slug}/version/{semver}", + "run": _smoke_case_5, + }, + + { + "operation": "updateApiDocumentVersion", + "method": "PATCH", + "path": "/v1/apis/{namespace}/{slug}/version/{semver}", + "run": _smoke_case_6, + }, + + { + "operation": "deleteApiDocumentVersion", + "method": "DELETE", + "path": "/v1/apis/{namespace}/{slug}/version/{semver}", + "run": _smoke_case_7, + }, + + { + "operation": "listApiDocumentVersionMetadata", + "method": "GET", + "path": "/v1/apis/{namespace}/{slug}/version/{semver}/metadata", + "run": _smoke_case_8, + }, + + { + "operation": "createApiDocumentVersion", + "method": "POST", + "path": "/v1/apis/{namespace}/{slug}/version", + "run": _smoke_case_9, + }, + + { + "operation": "createApiDocumentAccessGroup", + "method": "POST", + "path": "/v1/apis/{namespace}/{slug}/access-group", + "run": _smoke_case_10, + }, + + { + "operation": "deleteApiDocumentAccessGroup", + "method": "DELETE", + "path": "/v1/apis/{namespace}/{slug}/access-group", + "run": _smoke_case_11, + }, + + { + "operation": "list", + "method": "GET", + "path": "/v1/schemas/{namespace}", + "run": _smoke_case_12, + }, + + { + "operation": "create", + "method": "POST", + "path": "/v1/schemas/{namespace}", + "run": _smoke_case_13, + }, + + { + "operation": "update", + "method": "PATCH", + "path": "/v1/schemas/{namespace}/{slug}", + "run": _smoke_case_14, + }, + + { + "operation": "delete", + "method": "DELETE", + "path": "/v1/schemas/{namespace}/{slug}", + "run": _smoke_case_15, + }, + + { + "operation": "retrieveSchema", + "method": "GET", + "path": "/v1/schemas/{namespace}/{slug}/version/{semver}", + "run": _smoke_case_16, + }, + + { + "operation": "deleteSchema", + "method": "DELETE", + "path": "/v1/schemas/{namespace}/{slug}/version/{semver}", + "run": _smoke_case_17, + }, + + { + "operation": "createSchema", + "method": "POST", + "path": "/v1/schemas/{namespace}/{slug}/version", + "run": _smoke_case_18, + }, + + { + "operation": "createSchema", + "method": "POST", + "path": "/v1/schemas/{namespace}/{slug}/access-group", + "run": _smoke_case_19, + }, + + { + "operation": "deleteSchema", + "method": "DELETE", + "path": "/v1/schemas/{namespace}/{slug}/access-group", + "run": _smoke_case_20, + }, + + { + "operation": "retrieve", + "method": "GET", + "path": "/v1/login-portals/{slug}", + "run": _smoke_case_21, + }, + + { + "operation": "update", + "method": "PATCH", + "path": "/v1/login-portals/{slug}", + "run": _smoke_case_22, + }, + + { + "operation": "delete", + "method": "DELETE", + "path": "/v1/login-portals/{slug}", + "run": _smoke_case_23, + }, + + { + "operation": "create", + "method": "POST", + "path": "/v1/login-portals", + "run": _smoke_case_24, + }, + + { + "operation": "list", + "method": "GET", + "path": "/v1/login-portals", + "run": _smoke_case_25, + }, + + { + "operation": "listRulesets", + "method": "GET", + "path": "/v1/rulesets/{namespace}", + "run": _smoke_case_26, + }, + + { + "operation": "createRuleset", + "method": "POST", + "path": "/v1/rulesets/{namespace}", + "run": _smoke_case_27, + }, + + { + "operation": "updateRuleset", + "method": "PATCH", + "path": "/v1/rulesets/{namespace}/{slug}", + "run": _smoke_case_28, + }, + + { + "operation": "deleteRuleset", + "method": "DELETE", + "path": "/v1/rulesets/{namespace}/{slug}", + "run": _smoke_case_29, + }, + + { + "operation": "retrieveRulesetDocument", + "method": "GET", + "path": "/v1/rulesets/{namespace}/{slug}", + "run": _smoke_case_30, + }, + + { + "operation": "createRulesetAccessGroup", + "method": "POST", + "path": "/v1/rulesets/{namespace}/{slug}/access-group", + "run": _smoke_case_31, + }, + + { + "operation": "deleteRulesetAccessGroup", + "method": "DELETE", + "path": "/v1/rulesets/{namespace}/{slug}/access-group", + "run": _smoke_case_32, + }, + + { + "operation": "list", + "method": "GET", + "path": "/v1/themes", + "run": _smoke_case_33, + }, + + { + "operation": "create", + "method": "POST", + "path": "/v1/themes", + "run": _smoke_case_34, + }, + + { + "operation": "update", + "method": "PATCH", + "path": "/v1/themes/{slug}", + "run": _smoke_case_35, + }, + + { + "operation": "replaceDocument", + "method": "PUT", + "path": "/v1/themes/{slug}", + "run": _smoke_case_36, + }, + + { + "operation": "delete", + "method": "DELETE", + "path": "/v1/themes/{slug}", + "run": _smoke_case_37, + }, + + { + "operation": "retrieve", + "method": "GET", + "path": "/v1/themes/{slug}", + "run": _smoke_case_38, + }, + + { + "operation": "list", + "method": "GET", + "path": "/v1/teams", + "run": _smoke_case_39, + }, + + { + "operation": "listGuides", + "method": "GET", + "path": "/v1/guides", + "run": _smoke_case_40, + }, + + { + "operation": "createGuide", + "method": "POST", + "path": "/v1/guides", + "run": _smoke_case_41, + }, + + { + "operation": "publishGuide", + "method": "POST", + "path": "/v1/guides/{slug}/publish", + "run": _smoke_case_42, + }, + + { + "operation": "list", + "method": "GET", + "path": "/v1/namespaces", + "run": _smoke_case_43, + }, + + { + "operation": "exchangePersonalToken", + "method": "POST", + "path": "/v1/auth/exchange", + "run": _smoke_case_44, + }, + + { + "operation": "listCurrentUser", + "method": "GET", + "path": "/v1/auth/me", + "run": _smoke_case_45, + }, + +] + +def _selected_cases() -> list[SmokeCase]: + filter_value = os.environ.get("SCALAR_SMOKE_FILTER") + needles = [needle.strip() for needle in filter_value.split(",") if needle.strip()] if filter_value else [] + if not needles: + return cases + return [ + case + for case in cases + if any(needle in case["operation"] or needle in case["path"] for needle in needles) + ] + + +def _run_case(case: SmokeCase) -> SmokeResult: + started_at = time.monotonic() + try: + case["run"]() + return { + "operation": case["operation"], + "method": case["method"], + "path": case["path"], + "status": "passed", + "durationMs": int((time.monotonic() - started_at) * 1000), + } + except Exception: + return { + "operation": case["operation"], + "method": case["method"], + "path": case["path"], + "status": "failed", + "durationMs": int((time.monotonic() - started_at) * 1000), + "error": traceback.format_exc(), + } + + +def main() -> None: + selected = _selected_cases() + if selected: + with ThreadPoolExecutor(max_workers=len(selected)) as executor: + results = list(executor.map(_run_case, selected)) + else: + results = [] + failed = [result for result in results if result["status"] == "failed"] + + report_path = os.environ.get("SCALAR_SMOKE_REPORT") + if report_path: + Path(report_path).write_text(json.dumps({"total": len(results), "failed": len(failed), "results": results}), encoding="utf-8") + else: + for result in results: + if result["status"] == "passed": + print(f"PASS {result['operation']} ({result['method']} {result['path']}) {result['durationMs']}ms") + else: + print(f"FAIL {result['operation']} ({result['method']} {result['path']})\n{result.get('error', '')}", file=sys.stderr) + if not results: + print("No code samples ran (empty SDK or a SCALAR_SMOKE_FILTER that matched nothing).", file=sys.stderr) + else: + print(f"\n{len(results) - len(failed)}/{len(results)} samples passed") + + if failed or not results: + sys.exit(1) + + +if __name__ == "__main__": + main()