diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 77eecb6..383fcee 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -24,6 +24,39 @@ jobs: - name: Type-check run: mypy src - name: Test - run: pytest -q + run: pytest -q -m "not live" - name: Build wheel run: pip install build && python -m build --wheel + + live: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-python@v5 + with: + python-version: "3.12" + - name: Install + run: pip install -e ".[dev,grpc]" + # Authorizer v2 is configured via CLI flags (not env vars), so the server + # is started with `docker run` rather than a `services:` block. gRPC needs + # its own port (9091) and --grpc-insecure for plaintext CI testing. + - name: Start Authorizer + run: | + docker run -d --name authorizer \ + -p 8080:8080 -p 9091:9091 \ + quay.io/authorizer/authorizer:2.3.0 \ + --database-type=sqlite --database-url=test.db \ + --jwt-type=HS256 --jwt-secret=test \ + --admin-secret=admin --client-id=ci-client --client-secret=secret \ + --grpc-insecure=true + for i in $(seq 1 30); do + curl -fsS http://localhost:8080/health && break || sleep 2 + done + - name: Live integration tests + env: + AUTHORIZER_TEST_URL: http://localhost:8080 + AUTHORIZER_TEST_GRPC: localhost:9091 + AUTHORIZER_TEST_CLIENT_ID: ci-client + AUTHORIZER_ADMIN_SECRET: admin + AUTHORIZER_PROTOCOLS: graphql,rest,grpc + run: pytest tests/integration -m live -q diff --git a/README.md b/README.md index 748bd46..b229853 100644 --- a/README.md +++ b/README.md @@ -21,6 +21,8 @@ pip install authorizer-py | `authorizer_url` | Yes | Base URL of your Authorizer instance (no trailing slash) | | `redirect_url` | No | Default redirect URL used by magic-link and forgot-password flows | | `extra_headers` | No | Additional headers sent on every request (e.g. custom `Origin`) | +| `protocol` | No | Transport: `"graphql"` (default), `"rest"`, or `"grpc"` | +| `grpc_endpoint` | No | gRPC target `host:port`. The server's gRPC listener runs on a **separate port** (default `9091`), not the HTTP URL's port. When unset, the host is derived from `authorizer_url` and port `9091` is used. Only used when `protocol="grpc"`. | **Sync:** @@ -115,6 +117,31 @@ print("can view:", accessible.objects) client.close() ``` +## gRPC transport + +Set `protocol="grpc"` to call the server over gRPC. This requires the optional +gRPC dependencies: + +```bash +pip install 'authorizer-py[grpc]' +``` + +The server's gRPC listener runs on a **separate port** (default `9091`), not the +HTTP URL's port (`8080`). When `grpc_endpoint` is unset, the host is taken from +`authorizer_url` and port `9091` is used; pass `grpc_endpoint` to dial a custom +target explicitly: + +```python +from authorizer import AuthorizerClient + +client = AuthorizerClient( + client_id="YOUR_CLIENT_ID", + authorizer_url="https://your-instance.authorizer.dev", + protocol="grpc", + grpc_endpoint="your-instance.authorizer.dev:9091", # optional; defaults to host:9091 +) +``` + ## License Apache-2.0 — see [LICENSE](LICENSE) for details. diff --git a/examples/manual_test.py b/examples/manual_test.py new file mode 100644 index 0000000..9022b52 --- /dev/null +++ b/examples/manual_test.py @@ -0,0 +1,154 @@ +"""Manual end-to-end smoke test for the Authorizer Python SDK. + +Exercises the public client (meta/signup/login/profile) and the admin client +(users/webhooks/FGA) over the protocol you pick. + +Setup + run (defaults shown): + + python -m venv .venv + ./.venv/bin/pip install -e ".[grpc]" # drop [grpc] if you only use graphql/rest + + AUTHORIZER_URL=http://localhost:8080 \ + CLIENT_ID=test-client \ + ADMIN_SECRET=admin \ + PROTOCOL=graphql \ # graphql | rest | grpc + ./.venv/bin/python examples/manual_test.py + +gRPC listens on its own port (default :9091); override with GRPC_ENDPOINT=host:port. +For plaintext gRPC the server must run with --grpc-insecure=true. +""" + +from __future__ import annotations + +import os +import time + +from authorizer import ( + AddWebhookRequest, + AuthorizerAdminClient, + AuthorizerClient, + FgaReadTuplesRequest, + FgaTupleInput, + FgaWriteModelRequest, + FgaWriteTuplesRequest, + LoginRequest, + SignUpRequest, + WebhookRequest, +) +from authorizer.exceptions import AuthorizerError + +URL = os.getenv("AUTHORIZER_URL", "http://localhost:8080") +CLIENT_ID = os.getenv("CLIENT_ID", "test-client") +ADMIN_SECRET = os.getenv("ADMIN_SECRET", "admin") +PROTOCOL = os.getenv("PROTOCOL", "graphql") # graphql | rest | grpc +GRPC_ENDPOINT = os.getenv("GRPC_ENDPOINT", "") + +FGA_MODEL = """model + schema 1.1 +type user +type document + relations + define viewer: [user]""" + + +def step(label: str, fn) -> None: + """Run fn(), print result; never abort so the whole flow runs.""" + try: + result = fn() + print(f"✓ {label:<22} {result}") + except AuthorizerError as exc: # noqa: BLE001 - demo wants every call attempted + print(f"✗ {label:<22} error: {exc}") + except Exception as exc: # noqa: BLE001 + print(f"✗ {label:<22} error: {exc}") + + +def main() -> None: + print(f"== Authorizer Python SDK manual test ==\nurl={URL} protocol={PROTOCOL}\n") + + client = AuthorizerClient( + client_id=CLIENT_ID, + authorizer_url=URL, + protocol=PROTOCOL, + grpc_endpoint=GRPC_ENDPOINT, + ) + + step("get_meta_data", lambda: client.get_meta_data()) + + email = f"py-manual-{time.time_ns()}@example.com" + step( + "signup", + lambda: client.signup( + SignUpRequest(email=email, password="Test@12345", confirm_password="Test@12345") + ), + ) + + auth = None + + def _login(): + nonlocal auth + auth = client.login(LoginRequest(email=email, password="Test@12345")) + return f"access_token={'set' if auth.access_token else 'none'}" + + step("login", _login) + + if auth and auth.access_token: + step( + "get_profile", + lambda: client.get_profile({"Authorization": f"Bearer {auth.access_token}"}), + ) + + # ---- Admin client (auth via x-authorizer-admin-secret) ---- + print("\n-- admin --") + admin = AuthorizerAdminClient( + authorizer_url=URL, + admin_secret=ADMIN_SECRET, + protocol=PROTOCOL, + grpc_endpoint=GRPC_ENDPOINT, + ) + + step("users", lambda: f"{len(admin.users().users)} user(s)") + + webhook_endpoint = "https://example.com/webhook" + step( + "add_webhook", + lambda: admin.add_webhook( + AddWebhookRequest( + event_name="user.login", + endpoint=webhook_endpoint, + enabled=True, + ) + ), + ) + + def _list_and_clean(): + resp = admin.webhooks() + # Clean up by endpoint: the server appends a "-" suffix to + # event_name (not a stable key); endpoint is stored verbatim. + deleted = 0 + for w in resp.webhooks: + if w.endpoint == webhook_endpoint: + admin.delete_webhook(WebhookRequest(id=w.id)) + deleted += 1 + return f"{len(resp.webhooks)} webhook(s); deleted {deleted}" + + step("webhooks + cleanup", _list_and_clean) + + # ---- FGA admin ---- + print("\n-- fga admin --") + step("fga_write_model", lambda: admin.fga_write_model(FgaWriteModelRequest(dsl=FGA_MODEL))) + fga_object = f"document:{time.time_ns()}" # unique so re-runs don't collide + step( + "fga_write_tuples", + lambda: admin.fga_write_tuples( + FgaWriteTuplesRequest( + tuples=[FgaTupleInput(user="user:alice", relation="viewer", object=fga_object)] + ) + ), + ) + step("fga_read_tuples", lambda: f"{len(admin.fga_read_tuples(FgaReadTuplesRequest()).tuples)} tuple(s)") + + print("\ndone.") + + +if __name__ == "__main__": + main() diff --git a/pyproject.toml b/pyproject.toml index 69cc443..e9f8df4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -23,10 +23,22 @@ classifiers = [ "Programming Language :: Python :: 3.13", "Typing :: Typed", ] -dependencies = ["httpx>=0.24,<1"] +# protobuf is a base dependency: the REST protocol parses grpc-gateway responses +# with protojson (int64-as-string + single-field wrappers) using the vendored +# proto message types. grpcio is only needed for the optional ``grpc`` protocol. +dependencies = ["httpx>=0.24,<1", "protobuf>=4"] [project.optional-dependencies] -dev = ["pytest>=7", "pytest-asyncio>=0.23", "respx>=0.20", "ruff>=0.5", "mypy>=1.8"] +grpc = ["grpcio>=1.60", "protobuf>=4"] +dev = [ + "pytest>=7", + "pytest-asyncio>=0.23", + "respx>=0.20", + "ruff>=0.5", + "mypy>=1.8", + "grpcio>=1.60", + "protobuf>=4", +] [project.urls] Homepage = "https://authorizer.dev" @@ -39,6 +51,8 @@ packages = ["src/authorizer"] [tool.ruff] line-length = 100 target-version = "py39" +# Vendored generated gRPC/protobuf stubs — never lint. +extend-exclude = ["src/authorizer/_grpc"] [tool.ruff.lint] select = ["E", "F", "I", "UP", "B", "W"] @@ -47,7 +61,21 @@ select = ["E", "F", "I", "UP", "B", "W"] python_version = "3.9" strict = true warn_unused_ignores = true +# Vendored generated gRPC/protobuf stubs — not type-checked. +exclude = ["src/authorizer/_grpc/"] + +[[tool.mypy.overrides]] +module = "authorizer._grpc.*" +ignore_errors = true +ignore_missing_imports = true + +[[tool.mypy.overrides]] +module = ["grpc", "grpc.*", "google.protobuf.*"] +ignore_missing_imports = true [tool.pytest.ini_options] asyncio_mode = "auto" testpaths = ["tests"] +markers = [ + "live: integration tests that hit a real Authorizer server (deselect with -m 'not live')", +] diff --git a/src/authorizer/__init__.py b/src/authorizer/__init__.py index d9ca8e9..148cde6 100644 --- a/src/authorizer/__init__.py +++ b/src/authorizer/__init__.py @@ -2,25 +2,58 @@ from __future__ import annotations +from .admin_client import AuthorizerAdminClient +from .async_admin_client import AsyncAuthorizerAdminClient from .async_client import AsyncAuthorizerClient from .client import AuthorizerClient from .exceptions import AuthorizerConnectionError, AuthorizerError from .types import ( + AddEmailTemplateRequest, + AddWebhookRequest, + AdminLoginRequest, + AdminMeta, + AdminSignupRequest, + AuditLog, + AuditLogsResponse, AuthToken, CheckPermissionsRequest, CheckPermissionsResponse, + DeleteEmailTemplateRequest, + DeleteUserRequest, + EmailTemplate, + EmailTemplatesResponse, + FgaExpandRequest, + FgaExpandResponse, + FgaListUsersRequest, + FgaListUsersResponse, + FgaModel, + FgaReadTuplesRequest, + FgaReadTuplesResponse, + FgaTuple, FgaTupleInput, + FgaWriteModelRequest, + FgaWriteTuplesRequest, ForgotPasswordRequest, ForgotPasswordResponse, + GenerateJWTKeysRequest, + GenerateJWTKeysResponse, GenericResponse, GetTokenRequest, GetTokenResponse, + GetUserRequest, + InviteMembersRequest, + InviteMembersResponse, + ListAuditLogRequest, ListPermissionsRequest, ListPermissionsResponse, + ListWebhookLogRequest, LoginRequest, MagicLinkLoginRequest, MetaData, OAuthProviders, + PaginatedRequest, + Pagination, + PaginationRequest, Permission, PermissionCheckInput, PermissionCheckResult, @@ -31,15 +64,29 @@ RevokeTokenRequest, SessionQueryRequest, SignUpRequest, + TestEndpointRequest, + TestEndpointResponse, TokenType, + UpdateAccessRequest, + UpdateEmailTemplateRequest, UpdateProfileRequest, + UpdateUserRequest, + UpdateWebhookRequest, User, + UsersResponse, ValidateJWTTokenRequest, ValidateJWTTokenResponse, ValidateSessionRequest, ValidateSessionResponse, + VerificationRequest, + VerificationRequestsResponse, VerifyEmailRequest, VerifyOTPRequest, + Webhook, + WebhookLog, + WebhookLogsResponse, + WebhookRequest, + WebhooksResponse, ) __version__ = "0.1.0" @@ -47,23 +94,56 @@ __all__ = [ "AuthorizerClient", "AsyncAuthorizerClient", + "AuthorizerAdminClient", + "AsyncAuthorizerAdminClient", "AuthorizerError", "AuthorizerConnectionError", + "AddEmailTemplateRequest", + "AddWebhookRequest", + "AdminLoginRequest", + "AdminMeta", + "AdminSignupRequest", + "AuditLog", + "AuditLogsResponse", "AuthToken", "CheckPermissionsRequest", "CheckPermissionsResponse", + "DeleteEmailTemplateRequest", + "DeleteUserRequest", + "EmailTemplate", + "EmailTemplatesResponse", + "FgaExpandRequest", + "FgaExpandResponse", + "FgaListUsersRequest", + "FgaListUsersResponse", + "FgaModel", + "FgaReadTuplesRequest", + "FgaReadTuplesResponse", + "FgaTuple", "FgaTupleInput", + "FgaWriteModelRequest", + "FgaWriteTuplesRequest", "ForgotPasswordRequest", "ForgotPasswordResponse", + "GenerateJWTKeysRequest", + "GenerateJWTKeysResponse", "GenericResponse", "GetTokenRequest", "GetTokenResponse", + "GetUserRequest", + "InviteMembersRequest", + "InviteMembersResponse", + "ListAuditLogRequest", "ListPermissionsRequest", "ListPermissionsResponse", + "ListWebhookLogRequest", "LoginRequest", "MagicLinkLoginRequest", "MetaData", "OAuthProviders", + "Pagination", + "PaginatedRequest", + "PaginationRequest", "Permission", "PermissionCheckInput", "PermissionCheckResult", @@ -74,14 +154,28 @@ "RevokeTokenRequest", "SessionQueryRequest", "SignUpRequest", + "TestEndpointRequest", + "TestEndpointResponse", "TokenType", + "UpdateAccessRequest", + "UpdateEmailTemplateRequest", "UpdateProfileRequest", + "UpdateUserRequest", + "UpdateWebhookRequest", "User", + "UsersResponse", "ValidateJWTTokenRequest", "ValidateJWTTokenResponse", "ValidateSessionRequest", "ValidateSessionResponse", + "VerificationRequest", + "VerificationRequestsResponse", "VerifyEmailRequest", "VerifyOTPRequest", + "Webhook", + "WebhookLog", + "WebhookLogsResponse", + "WebhookRequest", + "WebhooksResponse", "__version__", ] diff --git a/src/authorizer/_core.py b/src/authorizer/_core.py index 50ec3cf..6a3550e 100644 --- a/src/authorizer/_core.py +++ b/src/authorizer/_core.py @@ -9,6 +9,11 @@ from .exceptions import AuthorizerError +# Supported transport protocols. ``graphql`` is the default (100% backward +# compatible). ``rest`` maps to the public/admin proto google.api.http paths; +# ``grpc`` calls the vendored stubs (requires the optional ``grpc`` extra). +PROTOCOLS = ("graphql", "rest", "grpc") + @dataclass class ClientConfig: @@ -16,6 +21,12 @@ class ClientConfig: authorizer_url: str redirect_url: str extra_headers: dict[str, str] + protocol: str = "graphql" + admin_secret: str = "" + # Explicit gRPC endpoint (host:port). The server's gRPC listener runs on a + # separate port (default 9091), not the HTTP URL's port. When unset, the + # gRPC target is derived from ``authorizer_url``'s host with port 9091. + grpc_endpoint: str = "" @dataclass @@ -40,6 +51,8 @@ def build_headers(config: ClientConfig, per_call: dict[str, str] | None) -> dict "x-authorizer-url": config.authorizer_url, "x-authorizer-client-id": config.client_id, } + if config.admin_secret: + headers["x-authorizer-admin-secret"] = config.admin_secret headers.update(config.extra_headers) if per_call: headers.update(per_call) @@ -74,6 +87,102 @@ def build_oauth_request( return RequestSpec("POST", f"{authorizer_url}{path}", headers, body) +def prepare_http( + config: ClientConfig, + spec: Any, + data: dict[str, Any] | None, + headers: dict[str, str] | None, +) -> tuple[RequestSpec, str, str | None]: + """Build the RequestSpec for graphql/rest from a MethodSpec + data. + + Returns ``(request_spec, kind, unwrap)`` where ``kind`` is ``"graphql"`` or + ``"rest"`` (selects the response parser) and ``unwrap`` is the response + field to extract (graphql field name, or the rest wrapper key). + """ + full_headers = build_headers(config, headers) + if config.protocol == "rest": + body = None if spec.rest_method == "GET" else (data or {}) + req = build_rest_request( + config.authorizer_url, spec.rest_method, spec.rest_path, body, full_headers + ) + return req, "rest", spec.rest_unwrap + variables = {"data": data} if data is not None else None + req = build_graphql_request(config.authorizer_url, spec.gql_query, variables, full_headers) + return req, "graphql", spec.gql_field + + +def build_rest_request( + authorizer_url: str, + method: str, + path: str, + body: dict[str, Any] | None, + headers: dict[str, str], +) -> RequestSpec: + """Build a REST request for a proto google.api.http annotated path.""" + return RequestSpec(method, f"{authorizer_url}{path}", headers, body or {}) + + +def raise_for_rest_error(status: int, body: bytes) -> None: + """Raise AuthorizerError for a failed grpc-gateway REST response (>= 400). + + Errors surface in a ``{"message": ..., "code": ...}`` shape; this runs before + protojson parsing because the error body is not a valid proto response. + """ + if status < 400: + return + decoded = _decode(body) + message = f"HTTP {status}" + if isinstance(decoded, dict): + message = str(decoded.get("message") or decoded.get("error") or message) + text = body.decode("utf-8", "replace") if not isinstance(decoded, dict) else "" + raise AuthorizerError(f"{message}: {text}".strip().rstrip(":").strip(), status=status) + + +def parse_rest_response( + status: int, body: bytes, unwrap: str | None +) -> dict[str, Any] | None: + """Parse a REST gateway JSON response with plain JSON (no proto types). + + Retained for REST methods that have no proto response message. The proto-typed + path (most methods) uses ``_grpc_transport.parse_rest_proto`` instead so int64 + strings and field names map correctly. + """ + raise_for_rest_error(status, body) + decoded = _decode(body) + if not isinstance(decoded, dict): + return None + if unwrap is None: + return decoded + inner = decoded.get(unwrap) + return inner if isinstance(inner, dict) else None + + +def parse_rest( + spec: Any, status: int, body: bytes, unwrap: str | None, admin: bool +) -> dict[str, Any] | None: + """Parse a REST response for a MethodSpec. + + Proto-backed REST methods (``spec.grpc_method`` set) are parsed with protojson + so int64/uint64 strings and field names map correctly; methods without a proto + response fall back to plain JSON. + """ + raise_for_rest_error(status, body) + if spec.grpc_method: + from ._proto import parse_rest_proto + + result = parse_rest_proto(body, spec.grpc_method, admin, unwrap) + return result if isinstance(result, dict) else None + return parse_rest_response(status, body, unwrap) + + +def unsupported_protocol_error(method: str, protocol: str, supported: tuple[str, ...]) -> Any: + """Build a clear AuthorizerError for a method called on an unsupported protocol.""" + alts = " or ".join(p for p in supported) if supported else "(none)" + return AuthorizerError( + f"{method} is not available over {protocol}; use {alts}" + ) + + def _decode(body: bytes) -> Any: if not body: return None diff --git a/src/authorizer/_dispatch.py b/src/authorizer/_dispatch.py new file mode 100644 index 0000000..ff7c8bd --- /dev/null +++ b/src/authorizer/_dispatch.py @@ -0,0 +1,270 @@ +"""Declarative per-method protocol descriptors shared by sync + async clients. + +Each :class:`MethodSpec` says how one logical SDK method maps onto each of the +three transports (graphql / rest / grpc). The clients hold one dispatcher that +reads these specs, so adding a method or fixing a mapping happens in one place +and sync/async stay in lock-step. +""" + +from __future__ import annotations + +from dataclasses import dataclass + +from . import _queries as q + + +@dataclass(frozen=True) +class MethodSpec: + protocols: tuple[str, ...] + # graphql + gql_query: str | None = None + gql_field: str | None = None + # rest + rest_method: str | None = None + rest_path: str | None = None + rest_unwrap: str | None = None + # grpc: stub attribute, request message name (in admin_pb2/authorizer_pb2), + # and the response field to unwrap (None = whole message). + grpc_method: str | None = None + grpc_request: str | None = None + grpc_response_unwrap: str | None = None + + +ALL = ("graphql", "rest", "grpc") +GQL_ONLY = ("graphql",) + + +# --------------------------------------------------------------------------- # +# Public (user) service methods +# --------------------------------------------------------------------------- # +# +# Protocol availability (server 2.3.0, PR #635 + #636): ALL 20 public RPCs +# now work over graphql + rest + grpc. There are no graphql-only public methods. +# The response envelope is FLATTENED: the bare domain message is returned +# (Signup/Login/Session/VerifyEmail/VerifyOtp -> AuthResponse, Profile -> User, +# Meta -> Meta), so the auth/user/meta wrapper unwrapping is gone -- responses +# map directly onto the SDK dataclasses. ``_proto._response_message_cls`` resolves +# each RPC's output type from the service descriptor, so it tracks these flat types +# automatically. Field names are snake_case and byte-identical to GraphQL. +PUBLIC: dict[str, MethodSpec] = { + "signup": MethodSpec( + ALL, q.SIGNUP, "signup", "POST", "/v1/signup", None, + "Signup", "SignupRequest", None, + ), + "login": MethodSpec( + ALL, q.LOGIN, "login", "POST", "/v1/login", None, + "Login", "LoginRequest", None, + ), + "magic_link_login": MethodSpec( + ALL, q.MAGIC_LINK_LOGIN, "magic_link_login", "POST", "/v1/magic_link_login", None, + "MagicLinkLogin", "MagicLinkLoginRequest", None, + ), + "verify_email": MethodSpec( + ALL, q.VERIFY_EMAIL, "verify_email", "POST", "/v1/verify_email", None, + "VerifyEmail", "VerifyEmailRequest", None, + ), + "resend_verify_email": MethodSpec( + ALL, q.RESEND_VERIFY_EMAIL, "resend_verify_email", + "POST", "/v1/resend_verify_email", None, + "ResendVerifyEmail", "ResendVerifyEmailRequest", None, + ), + "verify_otp": MethodSpec( + ALL, q.VERIFY_OTP, "verify_otp", "POST", "/v1/verify_otp", None, + "VerifyOtp", "VerifyOtpRequest", None, + ), + "resend_otp": MethodSpec( + ALL, q.RESEND_OTP, "resend_otp", "POST", "/v1/resend_otp", None, + "ResendOtp", "ResendOtpRequest", None, + ), + "forgot_password": MethodSpec( + ALL, q.FORGOT_PASSWORD, "forgot_password", "POST", "/v1/forgot_password", None, + "ForgotPassword", "ForgotPasswordRequest", None, + ), + "reset_password": MethodSpec( + ALL, q.RESET_PASSWORD, "reset_password", "POST", "/v1/reset_password", None, + "ResetPassword", "ResetPasswordRequest", None, + ), + "update_profile": MethodSpec( + ALL, q.UPDATE_PROFILE, "update_profile", "POST", "/v1/update_profile", None, + "UpdateProfile", "UpdateProfileRequest", None, + ), + "deactivate_account": MethodSpec( + ALL, q.DEACTIVATE_ACCOUNT, "deactivate_account", "POST", "/v1/deactivate_account", None, + "DeactivateAccount", "DeactivateAccountRequest", None, + ), + "validate_jwt_token": MethodSpec( + ALL, q.VALIDATE_JWT_TOKEN, "validate_jwt_token", "POST", "/v1/validate_jwt_token", None, + "ValidateJwtToken", "ValidateJwtTokenRequest", None, + ), + "validate_session": MethodSpec( + ALL, q.VALIDATE_SESSION, "validate_session", "POST", "/v1/validate_session", None, + "ValidateSession", "ValidateSessionRequest", None, + ), + "meta": MethodSpec( + ALL, q.META, "meta", "GET", "/v1/meta", None, "Meta", "MetaRequest", None + ), + "session": MethodSpec( + ALL, q.SESSION, "session", "POST", "/v1/session", None, + "Session", "SessionRequest", None, + ), + "profile": MethodSpec( + ALL, q.PROFILE, "profile", "GET", "/v1/profile", None, "Profile", "ProfileRequest", None + ), + "logout": MethodSpec( + ALL, q.LOGOUT, "logout", "POST", "/v1/logout", None, "Logout", "LogoutRequest", None + ), + "check_permissions": MethodSpec( + ALL, q.CHECK_PERMISSIONS, "check_permissions", "POST", "/v1/check_permissions", None, + "CheckPermissions", "CheckPermissionsRequest", None, + ), + "list_permissions": MethodSpec( + ALL, q.LIST_PERMISSIONS, "list_permissions", "POST", "/v1/list_permissions", None, + "ListPermissions", "ListPermissionsRequest", None, + ), +} + + +# --------------------------------------------------------------------------- # +# Admin service methods. ``rest_unwrap``/``grpc_response_unwrap`` name the single +# nested message on the response (None when the response is flat: a ``message`` +# string or a paginated list the dataclass reads whole). +# --------------------------------------------------------------------------- # +ADMIN: dict[str, MethodSpec] = { + "admin_login": MethodSpec( + ALL, q.ADMIN_LOGIN, "_admin_login", "POST", "/v1/admin/login", None, + "AdminLogin", "AdminLoginRequest", None, + ), + "admin_logout": MethodSpec( + ("rest", "grpc"), None, None, "POST", "/v1/admin/logout", None, + "AdminLogout", "AdminLogoutRequest", None, + ), + "admin_session": MethodSpec( + ("rest", "grpc"), None, None, "GET", "/v1/admin/session", None, + "AdminSession", "AdminSessionRequest", None, + ), + "admin_meta": MethodSpec( + ("rest", "grpc"), None, None, "GET", "/v1/admin/meta", "admin_meta", + "AdminMeta", "AdminMetaRequest", "admin_meta", + ), + "users": MethodSpec( + ALL, q.ADMIN_USERS, "_users", "POST", "/v1/admin/users", None, + "Users", "UsersRequest", None, + ), + "user": MethodSpec( + ALL, q.ADMIN_USER, "_user", "POST", "/v1/admin/user", "user", + "User", "UserRequest", "user", + ), + "update_user": MethodSpec( + ALL, q.ADMIN_UPDATE_USER, "_update_user", "POST", "/v1/admin/update_user", "user", + "UpdateUser", "UpdateUserRequest", "user", + ), + "delete_user": MethodSpec( + ALL, q.ADMIN_DELETE_USER, "_delete_user", "POST", "/v1/admin/delete_user", None, + "DeleteUser", "DeleteUserRequest", None, + ), + "verification_requests": MethodSpec( + ALL, q.ADMIN_VERIFICATION_REQUESTS, "_verification_requests", + "POST", "/v1/admin/verification_requests", None, + "VerificationRequests", "VerificationRequestsRequest", None, + ), + "revoke_access": MethodSpec( + ALL, q.ADMIN_REVOKE_ACCESS, "_revoke_access", "POST", "/v1/admin/revoke_access", None, + "RevokeAccess", "RevokeAccessRequest", None, + ), + "enable_access": MethodSpec( + ALL, q.ADMIN_ENABLE_ACCESS, "_enable_access", "POST", "/v1/admin/enable_access", None, + "EnableAccess", "EnableAccessRequest", None, + ), + "invite_members": MethodSpec( + ALL, q.ADMIN_INVITE_MEMBERS, "_invite_members", "POST", "/v1/admin/invite_members", None, + "InviteMembers", "InviteMembersRequest", None, + ), + "add_webhook": MethodSpec( + ALL, q.ADMIN_ADD_WEBHOOK, "_add_webhook", "POST", "/v1/admin/add_webhook", None, + "AddWebhook", "AddWebhookRequest", None, + ), + "update_webhook": MethodSpec( + ALL, q.ADMIN_UPDATE_WEBHOOK, "_update_webhook", "POST", "/v1/admin/update_webhook", None, + "UpdateWebhook", "UpdateWebhookRequest", None, + ), + "delete_webhook": MethodSpec( + ALL, q.ADMIN_DELETE_WEBHOOK, "_delete_webhook", "POST", "/v1/admin/delete_webhook", None, + "DeleteWebhook", "DeleteWebhookRequest", None, + ), + "get_webhook": MethodSpec( + ALL, q.ADMIN_GET_WEBHOOK, "_webhook", "POST", "/v1/admin/webhook", "webhook", + "GetWebhook", "GetWebhookRequest", "webhook", + ), + "webhooks": MethodSpec( + ALL, q.ADMIN_WEBHOOKS, "_webhooks", "POST", "/v1/admin/webhooks", None, + "Webhooks", "WebhooksRequest", None, + ), + "webhook_logs": MethodSpec( + ALL, q.ADMIN_WEBHOOK_LOGS, "_webhook_logs", "POST", "/v1/admin/webhook_logs", None, + "WebhookLogs", "WebhookLogsRequest", None, + ), + "test_endpoint": MethodSpec( + ALL, q.ADMIN_TEST_ENDPOINT, "_test_endpoint", "POST", "/v1/admin/test_endpoint", None, + "TestEndpoint", "TestEndpointRequest", None, + ), + "add_email_template": MethodSpec( + ALL, q.ADMIN_ADD_EMAIL_TEMPLATE, "_add_email_template", + "POST", "/v1/admin/add_email_template", None, + "AddEmailTemplate", "AddEmailTemplateRequest", None, + ), + "update_email_template": MethodSpec( + ALL, q.ADMIN_UPDATE_EMAIL_TEMPLATE, "_update_email_template", + "POST", "/v1/admin/update_email_template", None, + "UpdateEmailTemplate", "UpdateEmailTemplateRequest", None, + ), + "delete_email_template": MethodSpec( + ALL, q.ADMIN_DELETE_EMAIL_TEMPLATE, "_delete_email_template", + "POST", "/v1/admin/delete_email_template", None, + "DeleteEmailTemplate", "DeleteEmailTemplateRequest", None, + ), + "email_templates": MethodSpec( + ALL, q.ADMIN_EMAIL_TEMPLATES, "_email_templates", "POST", "/v1/admin/email_templates", None, + "EmailTemplates", "EmailTemplatesRequest", None, + ), + "audit_logs": MethodSpec( + ALL, q.ADMIN_AUDIT_LOGS, "_audit_logs", "POST", "/v1/admin/audit_logs", None, + "AuditLogs", "AuditLogsRequest", None, + ), + "fga_get_model": MethodSpec( + ("rest", "grpc"), None, None, "GET", "/v1/admin/fga/model", "model", + "FgaGetModel", "FgaGetModelRequest", "model", + ), + "fga_write_model": MethodSpec( + ALL, q.ADMIN_FGA_WRITE_MODEL, "_fga_write_model", "POST", "/v1/admin/fga/model", "model", + "FgaWriteModel", "FgaWriteModelRequest", "model", + ), + "fga_write_tuples": MethodSpec( + ALL, q.ADMIN_FGA_WRITE_TUPLES, "_fga_write_tuples", "POST", "/v1/admin/fga/tuples", None, + "FgaWriteTuples", "FgaWriteTuplesRequest", None, + ), + "fga_delete_tuples": MethodSpec( + ALL, q.ADMIN_FGA_DELETE_TUPLES, "_fga_delete_tuples", + "POST", "/v1/admin/fga/tuples/delete", None, + "FgaDeleteTuples", "FgaDeleteTuplesRequest", None, + ), + "fga_read_tuples": MethodSpec( + ALL, q.ADMIN_FGA_READ_TUPLES, "_fga_read_tuples", "POST", "/v1/admin/fga/tuples/read", None, + "FgaReadTuples", "FgaReadTuplesRequest", None, + ), + "fga_list_users": MethodSpec( + ALL, q.ADMIN_FGA_LIST_USERS, "_fga_list_users", "POST", "/v1/admin/fga/list_users", None, + "FgaListUsers", "FgaListUsersRequest", None, + ), + "fga_expand": MethodSpec( + ALL, q.ADMIN_FGA_EXPAND, "_fga_expand", "POST", "/v1/admin/fga/expand", None, + "FgaExpand", "FgaExpandRequest", None, + ), + "fga_reset": MethodSpec( + ("rest", "grpc"), None, None, "POST", "/v1/admin/fga/reset", None, + "FgaReset", "FgaResetRequest", None, + ), + # gql-only extras (no proto / no rest / no grpc). + "admin_signup": MethodSpec(GQL_ONLY, q.ADMIN_SIGNUP, "_admin_signup"), + "update_env": MethodSpec(GQL_ONLY, q.ADMIN_UPDATE_ENV, "_update_env"), + "generate_jwt_keys": MethodSpec(GQL_ONLY, q.ADMIN_GENERATE_JWT_KEYS, "_generate_jwt_keys"), +} diff --git a/src/authorizer/_grpc/__init__.py b/src/authorizer/_grpc/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/authorizer/_grpc/authorizer/__init__.py b/src/authorizer/_grpc/authorizer/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/authorizer/_grpc/authorizer/v1/__init__.py b/src/authorizer/_grpc/authorizer/v1/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/authorizer/_grpc/authorizer/v1/admin_pb2.py b/src/authorizer/_grpc/authorizer/v1/admin_pb2.py new file mode 100644 index 0000000..a5627d0 --- /dev/null +++ b/src/authorizer/_grpc/authorizer/v1/admin_pb2.py @@ -0,0 +1,297 @@ +# -*- coding: utf-8 -*- +# Generated by the protocol buffer compiler. DO NOT EDIT! +# NO CHECKED-IN PROTOBUF GENCODE +# source: authorizer/v1/admin.proto +# Protobuf Python Version: 5.27.3 +"""Generated protocol buffer code.""" +from google.protobuf import descriptor as _descriptor +from google.protobuf import descriptor_pool as _descriptor_pool +from google.protobuf import runtime_version as _runtime_version +from google.protobuf import symbol_database as _symbol_database +from google.protobuf.internal import builder as _builder +_runtime_version.ValidateProtobufRuntimeVersion( + _runtime_version.Domain.PUBLIC, + 5, + 27, + 3, + '', + 'authorizer/v1/admin.proto' +) +# @@protoc_insertion_point(imports) + +_sym_db = _symbol_database.Default() + + +from authorizer._grpc.authorizer.v1 import annotations_pb2 as authorizer_dot_v1_dot_annotations__pb2 +from authorizer._grpc.authorizer.v1 import common_pb2 as authorizer_dot_v1_dot_common__pb2 +from authorizer._grpc.authorizer.v1 import pagination_pb2 as authorizer_dot_v1_dot_pagination__pb2 +from authorizer._grpc.authorizer.v1 import types_pb2 as authorizer_dot_v1_dot_types__pb2 +from authorizer._grpc.buf.validate import validate_pb2 as buf_dot_validate_dot_validate__pb2 +from authorizer._grpc.google.api import annotations_pb2 as google_dot_api_dot_annotations__pb2 + + +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x19\x61uthorizer/v1/admin.proto\x12\rauthorizer.v1\x1a\x1f\x61uthorizer/v1/annotations.proto\x1a\x1a\x61uthorizer/v1/common.proto\x1a\x1e\x61uthorizer/v1/pagination.proto\x1a\x19\x61uthorizer/v1/types.proto\x1a\x1b\x62uf/validate/validate.proto\x1a\x1cgoogle/api/annotations.proto\"?\n\x11\x41\x64minLoginRequest\x12*\n\x0c\x61\x64min_secret\x18\x01 \x01(\tB\x07\xbaH\x04r\x02\x10\x01R\x0b\x61\x64minSecret\".\n\x12\x41\x64minLoginResponse\x12\x18\n\x07message\x18\x01 \x01(\tR\x07message\"\x14\n\x12\x41\x64minLogoutRequest\"/\n\x13\x41\x64minLogoutResponse\x12\x18\n\x07message\x18\x01 \x01(\tR\x07message\"\x15\n\x13\x41\x64minSessionRequest\"0\n\x14\x41\x64minSessionResponse\x12\x18\n\x07message\x18\x01 \x01(\tR\x07message\"\x12\n\x10\x41\x64minMetaRequest\"L\n\x11\x41\x64minMetaResponse\x12\x37\n\nadmin_meta\x18\x01 \x01(\x0b\x32\x18.authorizer.v1.AdminMetaR\tadminMeta\"o\n\tAdminMeta\x12\x14\n\x05roles\x18\x01 \x03(\tR\x05roles\x12#\n\rdefault_roles\x18\x02 \x03(\tR\x0c\x64\x65\x66\x61ultRoles\x12\'\n\x0fprotected_roles\x18\x03 \x03(\tR\x0eprotectedRoles\"P\n\x0cUsersRequest\x12@\n\npagination\x18\x01 \x01(\x0b\x32 .authorizer.v1.PaginationRequestR\npagination\"u\n\rUsersResponse\x12)\n\x05users\x18\x01 \x03(\x0b\x32\x13.authorizer.v1.UserR\x05users\x12\x39\n\npagination\x18\x02 \x01(\x0b\x32\x19.authorizer.v1.PaginationR\npagination\"3\n\x0bUserRequest\x12\x0e\n\x02id\x18\x01 \x01(\tR\x02id\x12\x14\n\x05\x65mail\x18\x02 \x01(\tR\x05\x65mail\"7\n\x0cUserResponse\x12\'\n\x04user\x18\x01 \x01(\x0b\x32\x13.authorizer.v1.UserR\x04user\"\x9c\x06\n\x11UpdateUserRequest\x12\x17\n\x02id\x18\x01 \x01(\tB\x07\xbaH\x04r\x02\x10\x01R\x02id\x12\x19\n\x05\x65mail\x18\x02 \x01(\tH\x00R\x05\x65mail\x88\x01\x01\x12*\n\x0e\x65mail_verified\x18\x03 \x01(\x08H\x01R\remailVerified\x88\x01\x01\x12\"\n\ngiven_name\x18\x04 \x01(\tH\x02R\tgivenName\x88\x01\x01\x12$\n\x0b\x66\x61mily_name\x18\x05 \x01(\tH\x03R\nfamilyName\x88\x01\x01\x12$\n\x0bmiddle_name\x18\x06 \x01(\tH\x04R\nmiddleName\x88\x01\x01\x12\x1f\n\x08nickname\x18\x07 \x01(\tH\x05R\x08nickname\x88\x01\x01\x12\x1b\n\x06gender\x18\x08 \x01(\tH\x06R\x06gender\x88\x01\x01\x12!\n\tbirthdate\x18\t \x01(\tH\x07R\tbirthdate\x88\x01\x01\x12&\n\x0cphone_number\x18\n \x01(\tH\x08R\x0bphoneNumber\x88\x01\x01\x12\x37\n\x15phone_number_verified\x18\x0b \x01(\x08H\tR\x13phoneNumberVerified\x88\x01\x01\x12\x1d\n\x07picture\x18\x0c \x01(\tH\nR\x07picture\x88\x01\x01\x12\x14\n\x05roles\x18\r \x03(\tR\x05roles\x12\x43\n\x1cis_multi_factor_auth_enabled\x18\x0e \x01(\x08H\x0bR\x18isMultiFactorAuthEnabled\x88\x01\x01\x12\x31\n\x08\x61pp_data\x18\x0f \x01(\x0b\x32\x16.authorizer.v1.AppDataR\x07\x61ppDataB\x08\n\x06_emailB\x11\n\x0f_email_verifiedB\r\n\x0b_given_nameB\x0e\n\x0c_family_nameB\x0e\n\x0c_middle_nameB\x0b\n\t_nicknameB\t\n\x07_genderB\x0c\n\n_birthdateB\x0f\n\r_phone_numberB\x18\n\x16_phone_number_verifiedB\n\n\x08_pictureB\x1f\n\x1d_is_multi_factor_auth_enabled\"=\n\x12UpdateUserResponse\x12\'\n\x04user\x18\x01 \x01(\x0b\x32\x13.authorizer.v1.UserR\x04user\"2\n\x11\x44\x65leteUserRequest\x12\x1d\n\x05\x65mail\x18\x01 \x01(\tB\x07\xbaH\x04r\x02\x10\x01R\x05\x65mail\".\n\x12\x44\x65leteUserResponse\x12\x18\n\x07message\x18\x01 \x01(\tR\x07message\"_\n\x1bVerificationRequestsRequest\x12@\n\npagination\x18\x01 \x01(\x0b\x32 .authorizer.v1.PaginationRequestR\npagination\"\xb2\x01\n\x1cVerificationRequestsResponse\x12W\n\x15verification_requests\x18\x01 \x03(\x0b\x32\".authorizer.v1.VerificationRequestR\x14verificationRequests\x12\x39\n\npagination\x18\x02 \x01(\x0b\x32\x19.authorizer.v1.PaginationR\npagination\"\x82\x02\n\x13VerificationRequest\x12\x0e\n\x02id\x18\x01 \x01(\tR\x02id\x12\x1e\n\nidentifier\x18\x02 \x01(\tR\nidentifier\x12\x14\n\x05token\x18\x03 \x01(\tR\x05token\x12\x14\n\x05\x65mail\x18\x04 \x01(\tR\x05\x65mail\x12\x18\n\x07\x65xpires\x18\x05 \x01(\x03R\x07\x65xpires\x12\x1d\n\ncreated_at\x18\x06 \x01(\x03R\tcreatedAt\x12\x1d\n\nupdated_at\x18\x07 \x01(\x03R\tupdatedAt\x12\x14\n\x05nonce\x18\x08 \x01(\tR\x05nonce\x12!\n\x0credirect_uri\x18\t \x01(\tR\x0bredirectUri\"7\n\x13RevokeAccessRequest\x12 \n\x07user_id\x18\x01 \x01(\tB\x07\xbaH\x04r\x02\x10\x01R\x06userId\"0\n\x14RevokeAccessResponse\x12\x18\n\x07message\x18\x01 \x01(\tR\x07message\"7\n\x13\x45nableAccessRequest\x12 \n\x07user_id\x18\x01 \x01(\tB\x07\xbaH\x04r\x02\x10\x01R\x06userId\"0\n\x14\x45nableAccessResponse\x12\x18\n\x07message\x18\x01 \x01(\tR\x07message\"g\n\x14InviteMembersRequest\x12\x16\n\x06\x65mails\x18\x01 \x03(\tR\x06\x65mails\x12&\n\x0credirect_uri\x18\x02 \x01(\tH\x00R\x0bredirectUri\x88\x01\x01\x42\x0f\n\r_redirect_uri\"\\\n\x15InviteMembersResponse\x12\x18\n\x07message\x18\x01 \x01(\tR\x07message\x12)\n\x05users\x18\x02 \x03(\x0b\x32\x13.authorizer.v1.UserR\x05users\"\x8b\x02\n\x07Webhook\x12\x0e\n\x02id\x18\x01 \x01(\tR\x02id\x12\x1d\n\nevent_name\x18\x02 \x01(\tR\teventName\x12+\n\x11\x65vent_description\x18\x03 \x01(\tR\x10\x65ventDescription\x12\x1a\n\x08\x65ndpoint\x18\x04 \x01(\tR\x08\x65ndpoint\x12\x18\n\x07\x65nabled\x18\x05 \x01(\x08R\x07\x65nabled\x12\x30\n\x07headers\x18\x06 \x01(\x0b\x32\x16.authorizer.v1.AppDataR\x07headers\x12\x1d\n\ncreated_at\x18\x07 \x01(\x03R\tcreatedAt\x12\x1d\n\nupdated_at\x18\x08 \x01(\x03R\tupdatedAt\"\xd0\x01\n\nWebhookLog\x12\x0e\n\x02id\x18\x01 \x01(\tR\x02id\x12\x1f\n\x0bhttp_status\x18\x02 \x01(\x03R\nhttpStatus\x12\x1a\n\x08response\x18\x03 \x01(\tR\x08response\x12\x18\n\x07request\x18\x04 \x01(\tR\x07request\x12\x1d\n\nwebhook_id\x18\x05 \x01(\tR\twebhookId\x12\x1d\n\ncreated_at\x18\x06 \x01(\x03R\tcreatedAt\x12\x1d\n\nupdated_at\x18\x07 \x01(\x03R\tupdatedAt\"\xf4\x01\n\x11\x41\x64\x64WebhookRequest\x12&\n\nevent_name\x18\x01 \x01(\tB\x07\xbaH\x04r\x02\x10\x01R\teventName\x12\x30\n\x11\x65vent_description\x18\x02 \x01(\tH\x00R\x10\x65ventDescription\x88\x01\x01\x12#\n\x08\x65ndpoint\x18\x03 \x01(\tB\x07\xbaH\x04r\x02\x10\x01R\x08\x65ndpoint\x12\x18\n\x07\x65nabled\x18\x04 \x01(\x08R\x07\x65nabled\x12\x30\n\x07headers\x18\x05 \x01(\x0b\x32\x16.authorizer.v1.AppDataR\x07headersB\x14\n\x12_event_description\".\n\x12\x41\x64\x64WebhookResponse\x12\x18\n\x07message\x18\x01 \x01(\tR\x07message\"\xb5\x02\n\x14UpdateWebhookRequest\x12\x17\n\x02id\x18\x01 \x01(\tB\x07\xbaH\x04r\x02\x10\x01R\x02id\x12\"\n\nevent_name\x18\x02 \x01(\tH\x00R\teventName\x88\x01\x01\x12\x30\n\x11\x65vent_description\x18\x03 \x01(\tH\x01R\x10\x65ventDescription\x88\x01\x01\x12\x1f\n\x08\x65ndpoint\x18\x04 \x01(\tH\x02R\x08\x65ndpoint\x88\x01\x01\x12\x1d\n\x07\x65nabled\x18\x05 \x01(\x08H\x03R\x07\x65nabled\x88\x01\x01\x12\x30\n\x07headers\x18\x06 \x01(\x0b\x32\x16.authorizer.v1.AppDataR\x07headersB\r\n\x0b_event_nameB\x14\n\x12_event_descriptionB\x0b\n\t_endpointB\n\n\x08_enabled\"1\n\x15UpdateWebhookResponse\x12\x18\n\x07message\x18\x01 \x01(\tR\x07message\"/\n\x14\x44\x65leteWebhookRequest\x12\x17\n\x02id\x18\x01 \x01(\tB\x07\xbaH\x04r\x02\x10\x01R\x02id\"1\n\x15\x44\x65leteWebhookResponse\x12\x18\n\x07message\x18\x01 \x01(\tR\x07message\",\n\x11GetWebhookRequest\x12\x17\n\x02id\x18\x01 \x01(\tB\x07\xbaH\x04r\x02\x10\x01R\x02id\"F\n\x12GetWebhookResponse\x12\x30\n\x07webhook\x18\x01 \x01(\x0b\x32\x16.authorizer.v1.WebhookR\x07webhook\"S\n\x0fWebhooksRequest\x12@\n\npagination\x18\x01 \x01(\x0b\x32 .authorizer.v1.PaginationRequestR\npagination\"\x81\x01\n\x10WebhooksResponse\x12\x32\n\x08webhooks\x18\x01 \x03(\x0b\x32\x16.authorizer.v1.WebhookR\x08webhooks\x12\x39\n\npagination\x18\x02 \x01(\x0b\x32\x19.authorizer.v1.PaginationR\npagination\"\x89\x01\n\x12WebhookLogsRequest\x12@\n\npagination\x18\x01 \x01(\x0b\x32 .authorizer.v1.PaginationRequestR\npagination\x12\"\n\nwebhook_id\x18\x02 \x01(\tH\x00R\twebhookId\x88\x01\x01\x42\r\n\x0b_webhook_id\"\x8e\x01\n\x13WebhookLogsResponse\x12<\n\x0cwebhook_logs\x18\x01 \x03(\x0b\x32\x19.authorizer.v1.WebhookLogR\x0bwebhookLogs\x12\x39\n\npagination\x18\x02 \x01(\x0b\x32\x19.authorizer.v1.PaginationR\npagination\"\xdc\x01\n\x13TestEndpointRequest\x12#\n\x08\x65ndpoint\x18\x01 \x01(\tB\x07\xbaH\x04r\x02\x10\x01R\x08\x65ndpoint\x12&\n\nevent_name\x18\x02 \x01(\tB\x07\xbaH\x04r\x02\x10\x01R\teventName\x12\x30\n\x11\x65vent_description\x18\x03 \x01(\tH\x00R\x10\x65ventDescription\x88\x01\x01\x12\x30\n\x07headers\x18\x04 \x01(\x0b\x32\x16.authorizer.v1.AppDataR\x07headersB\x14\n\x12_event_description\"S\n\x14TestEndpointResponse\x12\x1f\n\x0bhttp_status\x18\x01 \x01(\x03R\nhttpStatus\x12\x1a\n\x08response\x18\x02 \x01(\tR\x08response\"\xca\x01\n\rEmailTemplate\x12\x0e\n\x02id\x18\x01 \x01(\tR\x02id\x12\x1d\n\nevent_name\x18\x02 \x01(\tR\teventName\x12\x1a\n\x08template\x18\x03 \x01(\tR\x08template\x12\x16\n\x06\x64\x65sign\x18\x04 \x01(\tR\x06\x64\x65sign\x12\x18\n\x07subject\x18\x05 \x01(\tR\x07subject\x12\x1d\n\ncreated_at\x18\x06 \x01(\x03R\tcreatedAt\x12\x1d\n\nupdated_at\x18\x07 \x01(\x03R\tupdatedAt\"\xb1\x01\n\x17\x41\x64\x64\x45mailTemplateRequest\x12&\n\nevent_name\x18\x01 \x01(\tB\x07\xbaH\x04r\x02\x10\x01R\teventName\x12!\n\x07subject\x18\x02 \x01(\tB\x07\xbaH\x04r\x02\x10\x01R\x07subject\x12#\n\x08template\x18\x03 \x01(\tB\x07\xbaH\x04r\x02\x10\x01R\x08template\x12\x1b\n\x06\x64\x65sign\x18\x04 \x01(\tH\x00R\x06\x64\x65sign\x88\x01\x01\x42\t\n\x07_design\"4\n\x18\x41\x64\x64\x45mailTemplateResponse\x12\x18\n\x07message\x18\x01 \x01(\tR\x07message\"\xe9\x01\n\x1aUpdateEmailTemplateRequest\x12\x17\n\x02id\x18\x01 \x01(\tB\x07\xbaH\x04r\x02\x10\x01R\x02id\x12\"\n\nevent_name\x18\x02 \x01(\tH\x00R\teventName\x88\x01\x01\x12\x1f\n\x08template\x18\x03 \x01(\tH\x01R\x08template\x88\x01\x01\x12\x1d\n\x07subject\x18\x04 \x01(\tH\x02R\x07subject\x88\x01\x01\x12\x1b\n\x06\x64\x65sign\x18\x05 \x01(\tH\x03R\x06\x64\x65sign\x88\x01\x01\x42\r\n\x0b_event_nameB\x0b\n\t_templateB\n\n\x08_subjectB\t\n\x07_design\"7\n\x1bUpdateEmailTemplateResponse\x12\x18\n\x07message\x18\x01 \x01(\tR\x07message\"5\n\x1a\x44\x65leteEmailTemplateRequest\x12\x17\n\x02id\x18\x01 \x01(\tB\x07\xbaH\x04r\x02\x10\x01R\x02id\"7\n\x1b\x44\x65leteEmailTemplateResponse\x12\x18\n\x07message\x18\x01 \x01(\tR\x07message\"Y\n\x15\x45mailTemplatesRequest\x12@\n\npagination\x18\x01 \x01(\x0b\x32 .authorizer.v1.PaginationRequestR\npagination\"\x9a\x01\n\x16\x45mailTemplatesResponse\x12\x45\n\x0f\x65mail_templates\x18\x01 \x03(\x0b\x32\x1c.authorizer.v1.EmailTemplateR\x0e\x65mailTemplates\x12\x39\n\npagination\x18\x02 \x01(\x0b\x32\x19.authorizer.v1.PaginationR\npagination\"\xcc\x02\n\x08\x41uditLog\x12\x0e\n\x02id\x18\x01 \x01(\tR\x02id\x12\x19\n\x08\x61\x63tor_id\x18\x02 \x01(\tR\x07\x61\x63torId\x12\x1d\n\nactor_type\x18\x03 \x01(\tR\tactorType\x12\x1f\n\x0b\x61\x63tor_email\x18\x04 \x01(\tR\nactorEmail\x12\x16\n\x06\x61\x63tion\x18\x05 \x01(\tR\x06\x61\x63tion\x12#\n\rresource_type\x18\x06 \x01(\tR\x0cresourceType\x12\x1f\n\x0bresource_id\x18\x07 \x01(\tR\nresourceId\x12\x1d\n\nip_address\x18\x08 \x01(\tR\tipAddress\x12\x1d\n\nuser_agent\x18\t \x01(\tR\tuserAgent\x12\x1a\n\x08metadata\x18\n \x01(\tR\x08metadata\x12\x1d\n\ncreated_at\x18\x0b \x01(\x03R\tcreatedAt\"\x93\x03\n\x10\x41uditLogsRequest\x12@\n\npagination\x18\x01 \x01(\x0b\x32 .authorizer.v1.PaginationRequestR\npagination\x12\x1b\n\x06\x61\x63tion\x18\x02 \x01(\tH\x00R\x06\x61\x63tion\x88\x01\x01\x12\x1e\n\x08\x61\x63tor_id\x18\x03 \x01(\tH\x01R\x07\x61\x63torId\x88\x01\x01\x12(\n\rresource_type\x18\x04 \x01(\tH\x02R\x0cresourceType\x88\x01\x01\x12$\n\x0bresource_id\x18\x05 \x01(\tH\x03R\nresourceId\x88\x01\x01\x12*\n\x0e\x66rom_timestamp\x18\x06 \x01(\x03H\x04R\rfromTimestamp\x88\x01\x01\x12&\n\x0cto_timestamp\x18\x07 \x01(\x03H\x05R\x0btoTimestamp\x88\x01\x01\x42\t\n\x07_actionB\x0b\n\t_actor_idB\x10\n\x0e_resource_typeB\x0e\n\x0c_resource_idB\x11\n\x0f_from_timestampB\x0f\n\r_to_timestamp\"\x86\x01\n\x11\x41uditLogsResponse\x12\x36\n\naudit_logs\x18\x01 \x03(\x0b\x32\x17.authorizer.v1.AuditLogR\tauditLogs\x12\x39\n\npagination\x18\x02 \x01(\x0b\x32\x19.authorizer.v1.PaginationR\npagination\",\n\x08\x46gaModel\x12\x0e\n\x02id\x18\x01 \x01(\tR\x02id\x12\x10\n\x03\x64sl\x18\x02 \x01(\tR\x03\x64sl\"R\n\x08\x46gaTuple\x12\x12\n\x04user\x18\x01 \x01(\tR\x04user\x12\x1a\n\x08relation\x18\x02 \x01(\tR\x08relation\x12\x16\n\x06object\x18\x03 \x01(\tR\x06object\"\x14\n\x12\x46gaGetModelRequest\"D\n\x13\x46gaGetModelResponse\x12-\n\x05model\x18\x01 \x01(\x0b\x32\x17.authorizer.v1.FgaModelR\x05model\"1\n\x14\x46gaWriteModelRequest\x12\x19\n\x03\x64sl\x18\x01 \x01(\tB\x07\xbaH\x04r\x02\x10\x01R\x03\x64sl\"F\n\x15\x46gaWriteModelResponse\x12-\n\x05model\x18\x01 \x01(\x0b\x32\x17.authorizer.v1.FgaModelR\x05model\"M\n\x15\x46gaWriteTuplesRequest\x12\x34\n\x06tuples\x18\x01 \x03(\x0b\x32\x1c.authorizer.v1.FgaTupleInputR\x06tuples\"2\n\x16\x46gaWriteTuplesResponse\x12\x18\n\x07message\x18\x01 \x01(\tR\x07message\"N\n\x16\x46gaDeleteTuplesRequest\x12\x34\n\x06tuples\x18\x01 \x03(\x0b\x32\x1c.authorizer.v1.FgaTupleInputR\x06tuples\"3\n\x17\x46gaDeleteTuplesResponse\x12\x18\n\x07message\x18\x01 \x01(\tR\x07message\"\x89\x02\n\x14\x46gaReadTuplesRequest\x12\x17\n\x04user\x18\x01 \x01(\tH\x00R\x04user\x88\x01\x01\x12\x1f\n\x08relation\x18\x02 \x01(\tH\x01R\x08relation\x88\x01\x01\x12\x1b\n\x06object\x18\x03 \x01(\tH\x02R\x06object\x88\x01\x01\x12 \n\tpage_size\x18\x04 \x01(\x03H\x03R\x08pageSize\x88\x01\x01\x12\x32\n\x12\x63ontinuation_token\x18\x05 \x01(\tH\x04R\x11\x63ontinuationToken\x88\x01\x01\x42\x07\n\x05_userB\x0b\n\t_relationB\t\n\x07_objectB\x0c\n\n_page_sizeB\x15\n\x13_continuation_token\"\x93\x01\n\x15\x46gaReadTuplesResponse\x12/\n\x06tuples\x18\x01 \x03(\x0b\x32\x17.authorizer.v1.FgaTupleR\x06tuples\x12\x32\n\x12\x63ontinuation_token\x18\x02 \x01(\tH\x00R\x11\x63ontinuationToken\x88\x01\x01\x42\x15\n\x13_continuation_token\"\x81\x01\n\x13\x46gaListUsersRequest\x12\x1f\n\x06object\x18\x01 \x01(\tB\x07\xbaH\x04r\x02\x10\x01R\x06object\x12#\n\x08relation\x18\x02 \x01(\tB\x07\xbaH\x04r\x02\x10\x01R\x08relation\x12$\n\tuser_type\x18\x03 \x01(\tB\x07\xbaH\x04r\x02\x10\x01R\x08userType\",\n\x14\x46gaListUsersResponse\x12\x14\n\x05users\x18\x01 \x03(\tR\x05users\"X\n\x10\x46gaExpandRequest\x12#\n\x08relation\x18\x01 \x01(\tB\x07\xbaH\x04r\x02\x10\x01R\x08relation\x12\x1f\n\x06object\x18\x02 \x01(\tB\x07\xbaH\x04r\x02\x10\x01R\x06object\"\'\n\x11\x46gaExpandResponse\x12\x12\n\x04tree\x18\x01 \x01(\tR\x04tree\"\x11\n\x0f\x46gaResetRequest\",\n\x10\x46gaResetResponse\x12\x18\n\x07message\x18\x01 \x01(\tR\x07message2\xf5\x1e\n\x16\x41uthorizerAdminService\x12q\n\nAdminLogin\x12 .authorizer.v1.AdminLoginRequest\x1a!.authorizer.v1.AdminLoginResponse\"\x1e\xa0\xb5\x18\x01\x82\xd3\xe4\x93\x02\x14\"\x0f/v1/admin/login:\x01*\x12n\n\x0b\x41\x64minLogout\x12!.authorizer.v1.AdminLogoutRequest\x1a\".authorizer.v1.AdminLogoutResponse\"\x18\x82\xd3\xe4\x93\x02\x12\"\x10/v1/admin/logout\x12r\n\x0c\x41\x64minSession\x12\".authorizer.v1.AdminSessionRequest\x1a#.authorizer.v1.AdminSessionResponse\"\x19\x82\xd3\xe4\x93\x02\x13\x12\x11/v1/admin/session\x12\x66\n\tAdminMeta\x12\x1f.authorizer.v1.AdminMetaRequest\x1a .authorizer.v1.AdminMetaResponse\"\x16\x82\xd3\xe4\x93\x02\x10\x12\x0e/v1/admin/meta\x12^\n\x05Users\x12\x1b.authorizer.v1.UsersRequest\x1a\x1c.authorizer.v1.UsersResponse\"\x1a\x82\xd3\xe4\x93\x02\x14\"\x0f/v1/admin/users:\x01*\x12Z\n\x04User\x12\x1a.authorizer.v1.UserRequest\x1a\x1b.authorizer.v1.UserResponse\"\x19\x82\xd3\xe4\x93\x02\x13\"\x0e/v1/admin/user:\x01*\x12s\n\nUpdateUser\x12 .authorizer.v1.UpdateUserRequest\x1a!.authorizer.v1.UpdateUserResponse\" \x82\xd3\xe4\x93\x02\x1a\"\x15/v1/admin/update_user:\x01*\x12s\n\nDeleteUser\x12 .authorizer.v1.DeleteUserRequest\x1a!.authorizer.v1.DeleteUserResponse\" \x82\xd3\xe4\x93\x02\x1a\"\x15/v1/admin/delete_user:\x01*\x12\x9b\x01\n\x14VerificationRequests\x12*.authorizer.v1.VerificationRequestsRequest\x1a+.authorizer.v1.VerificationRequestsResponse\"*\x82\xd3\xe4\x93\x02$\"\x1f/v1/admin/verification_requests:\x01*\x12{\n\x0cRevokeAccess\x12\".authorizer.v1.RevokeAccessRequest\x1a#.authorizer.v1.RevokeAccessResponse\"\"\x82\xd3\xe4\x93\x02\x1c\"\x17/v1/admin/revoke_access:\x01*\x12{\n\x0c\x45nableAccess\x12\".authorizer.v1.EnableAccessRequest\x1a#.authorizer.v1.EnableAccessResponse\"\"\x82\xd3\xe4\x93\x02\x1c\"\x17/v1/admin/enable_access:\x01*\x12\x7f\n\rInviteMembers\x12#.authorizer.v1.InviteMembersRequest\x1a$.authorizer.v1.InviteMembersResponse\"#\x82\xd3\xe4\x93\x02\x1d\"\x18/v1/admin/invite_members:\x01*\x12s\n\nAddWebhook\x12 .authorizer.v1.AddWebhookRequest\x1a!.authorizer.v1.AddWebhookResponse\" \x82\xd3\xe4\x93\x02\x1a\"\x15/v1/admin/add_webhook:\x01*\x12\x7f\n\rUpdateWebhook\x12#.authorizer.v1.UpdateWebhookRequest\x1a$.authorizer.v1.UpdateWebhookResponse\"#\x82\xd3\xe4\x93\x02\x1d\"\x18/v1/admin/update_webhook:\x01*\x12\x7f\n\rDeleteWebhook\x12#.authorizer.v1.DeleteWebhookRequest\x1a$.authorizer.v1.DeleteWebhookResponse\"#\x82\xd3\xe4\x93\x02\x1d\"\x18/v1/admin/delete_webhook:\x01*\x12o\n\nGetWebhook\x12 .authorizer.v1.GetWebhookRequest\x1a!.authorizer.v1.GetWebhookResponse\"\x1c\x82\xd3\xe4\x93\x02\x16\"\x11/v1/admin/webhook:\x01*\x12j\n\x08Webhooks\x12\x1e.authorizer.v1.WebhooksRequest\x1a\x1f.authorizer.v1.WebhooksResponse\"\x1d\x82\xd3\xe4\x93\x02\x17\"\x12/v1/admin/webhooks:\x01*\x12w\n\x0bWebhookLogs\x12!.authorizer.v1.WebhookLogsRequest\x1a\".authorizer.v1.WebhookLogsResponse\"!\x82\xd3\xe4\x93\x02\x1b\"\x16/v1/admin/webhook_logs:\x01*\x12{\n\x0cTestEndpoint\x12\".authorizer.v1.TestEndpointRequest\x1a#.authorizer.v1.TestEndpointResponse\"\"\x82\xd3\xe4\x93\x02\x1c\"\x17/v1/admin/test_endpoint:\x01*\x12\x8c\x01\n\x10\x41\x64\x64\x45mailTemplate\x12&.authorizer.v1.AddEmailTemplateRequest\x1a\'.authorizer.v1.AddEmailTemplateResponse\"\'\x82\xd3\xe4\x93\x02!\"\x1c/v1/admin/add_email_template:\x01*\x12\x98\x01\n\x13UpdateEmailTemplate\x12).authorizer.v1.UpdateEmailTemplateRequest\x1a*.authorizer.v1.UpdateEmailTemplateResponse\"*\x82\xd3\xe4\x93\x02$\"\x1f/v1/admin/update_email_template:\x01*\x12\x98\x01\n\x13\x44\x65leteEmailTemplate\x12).authorizer.v1.DeleteEmailTemplateRequest\x1a*.authorizer.v1.DeleteEmailTemplateResponse\"*\x82\xd3\xe4\x93\x02$\"\x1f/v1/admin/delete_email_template:\x01*\x12\x83\x01\n\x0e\x45mailTemplates\x12$.authorizer.v1.EmailTemplatesRequest\x1a%.authorizer.v1.EmailTemplatesResponse\"$\x82\xd3\xe4\x93\x02\x1e\"\x19/v1/admin/email_templates:\x01*\x12o\n\tAuditLogs\x12\x1f.authorizer.v1.AuditLogsRequest\x1a .authorizer.v1.AuditLogsResponse\"\x1f\x82\xd3\xe4\x93\x02\x19\"\x14/v1/admin/audit_logs:\x01*\x12q\n\x0b\x46gaGetModel\x12!.authorizer.v1.FgaGetModelRequest\x1a\".authorizer.v1.FgaGetModelResponse\"\x1b\x82\xd3\xe4\x93\x02\x15\x12\x13/v1/admin/fga/model\x12z\n\rFgaWriteModel\x12#.authorizer.v1.FgaWriteModelRequest\x1a$.authorizer.v1.FgaWriteModelResponse\"\x1e\x82\xd3\xe4\x93\x02\x18\"\x13/v1/admin/fga/model:\x01*\x12~\n\x0e\x46gaWriteTuples\x12$.authorizer.v1.FgaWriteTuplesRequest\x1a%.authorizer.v1.FgaWriteTuplesResponse\"\x1f\x82\xd3\xe4\x93\x02\x19\"\x14/v1/admin/fga/tuples:\x01*\x12\x88\x01\n\x0f\x46gaDeleteTuples\x12%.authorizer.v1.FgaDeleteTuplesRequest\x1a&.authorizer.v1.FgaDeleteTuplesResponse\"&\x82\xd3\xe4\x93\x02 \"\x1b/v1/admin/fga/tuples/delete:\x01*\x12\x80\x01\n\rFgaReadTuples\x12#.authorizer.v1.FgaReadTuplesRequest\x1a$.authorizer.v1.FgaReadTuplesResponse\"$\x82\xd3\xe4\x93\x02\x1e\"\x19/v1/admin/fga/tuples/read:\x01*\x12|\n\x0c\x46gaListUsers\x12\".authorizer.v1.FgaListUsersRequest\x1a#.authorizer.v1.FgaListUsersResponse\"#\x82\xd3\xe4\x93\x02\x1d\"\x18/v1/admin/fga/list_users:\x01*\x12o\n\tFgaExpand\x12\x1f.authorizer.v1.FgaExpandRequest\x1a .authorizer.v1.FgaExpandResponse\"\x1f\x82\xd3\xe4\x93\x02\x19\"\x14/v1/admin/fga/expand:\x01*\x12k\n\x08\x46gaReset\x12\x1e.authorizer.v1.FgaResetRequest\x1a\x1f.authorizer.v1.FgaResetResponse\"\x1e\x82\xd3\xe4\x93\x02\x18\"\x13/v1/admin/fga/reset:\x01*B\xc6\x01\n\x11\x63om.authorizer.v1B\nAdminProtoP\x01ZPgithub.com/authorizerdev/authorizer-go/internal/genpb/authorizer/v1;authorizerv1\xa2\x02\x03\x41XX\xaa\x02\rAuthorizer.V1\xca\x02\rAuthorizer\\V1\xe2\x02\x19\x41uthorizer\\V1\\GPBMetadata\xea\x02\x0e\x41uthorizer::V1b\x06proto3') + +_globals = globals() +_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) +_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'authorizer.v1.admin_pb2', _globals) +if not _descriptor._USE_C_DESCRIPTORS: + _globals['DESCRIPTOR']._loaded_options = None + _globals['DESCRIPTOR']._serialized_options = b'\n\021com.authorizer.v1B\nAdminProtoP\001ZPgithub.com/authorizerdev/authorizer-go/internal/genpb/authorizer/v1;authorizerv1\242\002\003AXX\252\002\rAuthorizer.V1\312\002\rAuthorizer\\V1\342\002\031Authorizer\\V1\\GPBMetadata\352\002\016Authorizer::V1' + _globals['_ADMINLOGINREQUEST'].fields_by_name['admin_secret']._loaded_options = None + _globals['_ADMINLOGINREQUEST'].fields_by_name['admin_secret']._serialized_options = b'\272H\004r\002\020\001' + _globals['_UPDATEUSERREQUEST'].fields_by_name['id']._loaded_options = None + _globals['_UPDATEUSERREQUEST'].fields_by_name['id']._serialized_options = b'\272H\004r\002\020\001' + _globals['_DELETEUSERREQUEST'].fields_by_name['email']._loaded_options = None + _globals['_DELETEUSERREQUEST'].fields_by_name['email']._serialized_options = b'\272H\004r\002\020\001' + _globals['_REVOKEACCESSREQUEST'].fields_by_name['user_id']._loaded_options = None + _globals['_REVOKEACCESSREQUEST'].fields_by_name['user_id']._serialized_options = b'\272H\004r\002\020\001' + _globals['_ENABLEACCESSREQUEST'].fields_by_name['user_id']._loaded_options = None + _globals['_ENABLEACCESSREQUEST'].fields_by_name['user_id']._serialized_options = b'\272H\004r\002\020\001' + _globals['_ADDWEBHOOKREQUEST'].fields_by_name['event_name']._loaded_options = None + _globals['_ADDWEBHOOKREQUEST'].fields_by_name['event_name']._serialized_options = b'\272H\004r\002\020\001' + _globals['_ADDWEBHOOKREQUEST'].fields_by_name['endpoint']._loaded_options = None + _globals['_ADDWEBHOOKREQUEST'].fields_by_name['endpoint']._serialized_options = b'\272H\004r\002\020\001' + _globals['_UPDATEWEBHOOKREQUEST'].fields_by_name['id']._loaded_options = None + _globals['_UPDATEWEBHOOKREQUEST'].fields_by_name['id']._serialized_options = b'\272H\004r\002\020\001' + _globals['_DELETEWEBHOOKREQUEST'].fields_by_name['id']._loaded_options = None + _globals['_DELETEWEBHOOKREQUEST'].fields_by_name['id']._serialized_options = b'\272H\004r\002\020\001' + _globals['_GETWEBHOOKREQUEST'].fields_by_name['id']._loaded_options = None + _globals['_GETWEBHOOKREQUEST'].fields_by_name['id']._serialized_options = b'\272H\004r\002\020\001' + _globals['_TESTENDPOINTREQUEST'].fields_by_name['endpoint']._loaded_options = None + _globals['_TESTENDPOINTREQUEST'].fields_by_name['endpoint']._serialized_options = b'\272H\004r\002\020\001' + _globals['_TESTENDPOINTREQUEST'].fields_by_name['event_name']._loaded_options = None + _globals['_TESTENDPOINTREQUEST'].fields_by_name['event_name']._serialized_options = b'\272H\004r\002\020\001' + _globals['_ADDEMAILTEMPLATEREQUEST'].fields_by_name['event_name']._loaded_options = None + _globals['_ADDEMAILTEMPLATEREQUEST'].fields_by_name['event_name']._serialized_options = b'\272H\004r\002\020\001' + _globals['_ADDEMAILTEMPLATEREQUEST'].fields_by_name['subject']._loaded_options = None + _globals['_ADDEMAILTEMPLATEREQUEST'].fields_by_name['subject']._serialized_options = b'\272H\004r\002\020\001' + _globals['_ADDEMAILTEMPLATEREQUEST'].fields_by_name['template']._loaded_options = None + _globals['_ADDEMAILTEMPLATEREQUEST'].fields_by_name['template']._serialized_options = b'\272H\004r\002\020\001' + _globals['_UPDATEEMAILTEMPLATEREQUEST'].fields_by_name['id']._loaded_options = None + _globals['_UPDATEEMAILTEMPLATEREQUEST'].fields_by_name['id']._serialized_options = b'\272H\004r\002\020\001' + _globals['_DELETEEMAILTEMPLATEREQUEST'].fields_by_name['id']._loaded_options = None + _globals['_DELETEEMAILTEMPLATEREQUEST'].fields_by_name['id']._serialized_options = b'\272H\004r\002\020\001' + _globals['_FGAWRITEMODELREQUEST'].fields_by_name['dsl']._loaded_options = None + _globals['_FGAWRITEMODELREQUEST'].fields_by_name['dsl']._serialized_options = b'\272H\004r\002\020\001' + _globals['_FGALISTUSERSREQUEST'].fields_by_name['object']._loaded_options = None + _globals['_FGALISTUSERSREQUEST'].fields_by_name['object']._serialized_options = b'\272H\004r\002\020\001' + _globals['_FGALISTUSERSREQUEST'].fields_by_name['relation']._loaded_options = None + _globals['_FGALISTUSERSREQUEST'].fields_by_name['relation']._serialized_options = b'\272H\004r\002\020\001' + _globals['_FGALISTUSERSREQUEST'].fields_by_name['user_type']._loaded_options = None + _globals['_FGALISTUSERSREQUEST'].fields_by_name['user_type']._serialized_options = b'\272H\004r\002\020\001' + _globals['_FGAEXPANDREQUEST'].fields_by_name['relation']._loaded_options = None + _globals['_FGAEXPANDREQUEST'].fields_by_name['relation']._serialized_options = b'\272H\004r\002\020\001' + _globals['_FGAEXPANDREQUEST'].fields_by_name['object']._loaded_options = None + _globals['_FGAEXPANDREQUEST'].fields_by_name['object']._serialized_options = b'\272H\004r\002\020\001' + _globals['_AUTHORIZERADMINSERVICE'].methods_by_name['AdminLogin']._loaded_options = None + _globals['_AUTHORIZERADMINSERVICE'].methods_by_name['AdminLogin']._serialized_options = b'\240\265\030\001\202\323\344\223\002\024\"\017/v1/admin/login:\001*' + _globals['_AUTHORIZERADMINSERVICE'].methods_by_name['AdminLogout']._loaded_options = None + _globals['_AUTHORIZERADMINSERVICE'].methods_by_name['AdminLogout']._serialized_options = b'\202\323\344\223\002\022\"\020/v1/admin/logout' + _globals['_AUTHORIZERADMINSERVICE'].methods_by_name['AdminSession']._loaded_options = None + _globals['_AUTHORIZERADMINSERVICE'].methods_by_name['AdminSession']._serialized_options = b'\202\323\344\223\002\023\022\021/v1/admin/session' + _globals['_AUTHORIZERADMINSERVICE'].methods_by_name['AdminMeta']._loaded_options = None + _globals['_AUTHORIZERADMINSERVICE'].methods_by_name['AdminMeta']._serialized_options = b'\202\323\344\223\002\020\022\016/v1/admin/meta' + _globals['_AUTHORIZERADMINSERVICE'].methods_by_name['Users']._loaded_options = None + _globals['_AUTHORIZERADMINSERVICE'].methods_by_name['Users']._serialized_options = b'\202\323\344\223\002\024\"\017/v1/admin/users:\001*' + _globals['_AUTHORIZERADMINSERVICE'].methods_by_name['User']._loaded_options = None + _globals['_AUTHORIZERADMINSERVICE'].methods_by_name['User']._serialized_options = b'\202\323\344\223\002\023\"\016/v1/admin/user:\001*' + _globals['_AUTHORIZERADMINSERVICE'].methods_by_name['UpdateUser']._loaded_options = None + _globals['_AUTHORIZERADMINSERVICE'].methods_by_name['UpdateUser']._serialized_options = b'\202\323\344\223\002\032\"\025/v1/admin/update_user:\001*' + _globals['_AUTHORIZERADMINSERVICE'].methods_by_name['DeleteUser']._loaded_options = None + _globals['_AUTHORIZERADMINSERVICE'].methods_by_name['DeleteUser']._serialized_options = b'\202\323\344\223\002\032\"\025/v1/admin/delete_user:\001*' + _globals['_AUTHORIZERADMINSERVICE'].methods_by_name['VerificationRequests']._loaded_options = None + _globals['_AUTHORIZERADMINSERVICE'].methods_by_name['VerificationRequests']._serialized_options = b'\202\323\344\223\002$\"\037/v1/admin/verification_requests:\001*' + _globals['_AUTHORIZERADMINSERVICE'].methods_by_name['RevokeAccess']._loaded_options = None + _globals['_AUTHORIZERADMINSERVICE'].methods_by_name['RevokeAccess']._serialized_options = b'\202\323\344\223\002\034\"\027/v1/admin/revoke_access:\001*' + _globals['_AUTHORIZERADMINSERVICE'].methods_by_name['EnableAccess']._loaded_options = None + _globals['_AUTHORIZERADMINSERVICE'].methods_by_name['EnableAccess']._serialized_options = b'\202\323\344\223\002\034\"\027/v1/admin/enable_access:\001*' + _globals['_AUTHORIZERADMINSERVICE'].methods_by_name['InviteMembers']._loaded_options = None + _globals['_AUTHORIZERADMINSERVICE'].methods_by_name['InviteMembers']._serialized_options = b'\202\323\344\223\002\035\"\030/v1/admin/invite_members:\001*' + _globals['_AUTHORIZERADMINSERVICE'].methods_by_name['AddWebhook']._loaded_options = None + _globals['_AUTHORIZERADMINSERVICE'].methods_by_name['AddWebhook']._serialized_options = b'\202\323\344\223\002\032\"\025/v1/admin/add_webhook:\001*' + _globals['_AUTHORIZERADMINSERVICE'].methods_by_name['UpdateWebhook']._loaded_options = None + _globals['_AUTHORIZERADMINSERVICE'].methods_by_name['UpdateWebhook']._serialized_options = b'\202\323\344\223\002\035\"\030/v1/admin/update_webhook:\001*' + _globals['_AUTHORIZERADMINSERVICE'].methods_by_name['DeleteWebhook']._loaded_options = None + _globals['_AUTHORIZERADMINSERVICE'].methods_by_name['DeleteWebhook']._serialized_options = b'\202\323\344\223\002\035\"\030/v1/admin/delete_webhook:\001*' + _globals['_AUTHORIZERADMINSERVICE'].methods_by_name['GetWebhook']._loaded_options = None + _globals['_AUTHORIZERADMINSERVICE'].methods_by_name['GetWebhook']._serialized_options = b'\202\323\344\223\002\026\"\021/v1/admin/webhook:\001*' + _globals['_AUTHORIZERADMINSERVICE'].methods_by_name['Webhooks']._loaded_options = None + _globals['_AUTHORIZERADMINSERVICE'].methods_by_name['Webhooks']._serialized_options = b'\202\323\344\223\002\027\"\022/v1/admin/webhooks:\001*' + _globals['_AUTHORIZERADMINSERVICE'].methods_by_name['WebhookLogs']._loaded_options = None + _globals['_AUTHORIZERADMINSERVICE'].methods_by_name['WebhookLogs']._serialized_options = b'\202\323\344\223\002\033\"\026/v1/admin/webhook_logs:\001*' + _globals['_AUTHORIZERADMINSERVICE'].methods_by_name['TestEndpoint']._loaded_options = None + _globals['_AUTHORIZERADMINSERVICE'].methods_by_name['TestEndpoint']._serialized_options = b'\202\323\344\223\002\034\"\027/v1/admin/test_endpoint:\001*' + _globals['_AUTHORIZERADMINSERVICE'].methods_by_name['AddEmailTemplate']._loaded_options = None + _globals['_AUTHORIZERADMINSERVICE'].methods_by_name['AddEmailTemplate']._serialized_options = b'\202\323\344\223\002!\"\034/v1/admin/add_email_template:\001*' + _globals['_AUTHORIZERADMINSERVICE'].methods_by_name['UpdateEmailTemplate']._loaded_options = None + _globals['_AUTHORIZERADMINSERVICE'].methods_by_name['UpdateEmailTemplate']._serialized_options = b'\202\323\344\223\002$\"\037/v1/admin/update_email_template:\001*' + _globals['_AUTHORIZERADMINSERVICE'].methods_by_name['DeleteEmailTemplate']._loaded_options = None + _globals['_AUTHORIZERADMINSERVICE'].methods_by_name['DeleteEmailTemplate']._serialized_options = b'\202\323\344\223\002$\"\037/v1/admin/delete_email_template:\001*' + _globals['_AUTHORIZERADMINSERVICE'].methods_by_name['EmailTemplates']._loaded_options = None + _globals['_AUTHORIZERADMINSERVICE'].methods_by_name['EmailTemplates']._serialized_options = b'\202\323\344\223\002\036\"\031/v1/admin/email_templates:\001*' + _globals['_AUTHORIZERADMINSERVICE'].methods_by_name['AuditLogs']._loaded_options = None + _globals['_AUTHORIZERADMINSERVICE'].methods_by_name['AuditLogs']._serialized_options = b'\202\323\344\223\002\031\"\024/v1/admin/audit_logs:\001*' + _globals['_AUTHORIZERADMINSERVICE'].methods_by_name['FgaGetModel']._loaded_options = None + _globals['_AUTHORIZERADMINSERVICE'].methods_by_name['FgaGetModel']._serialized_options = b'\202\323\344\223\002\025\022\023/v1/admin/fga/model' + _globals['_AUTHORIZERADMINSERVICE'].methods_by_name['FgaWriteModel']._loaded_options = None + _globals['_AUTHORIZERADMINSERVICE'].methods_by_name['FgaWriteModel']._serialized_options = b'\202\323\344\223\002\030\"\023/v1/admin/fga/model:\001*' + _globals['_AUTHORIZERADMINSERVICE'].methods_by_name['FgaWriteTuples']._loaded_options = None + _globals['_AUTHORIZERADMINSERVICE'].methods_by_name['FgaWriteTuples']._serialized_options = b'\202\323\344\223\002\031\"\024/v1/admin/fga/tuples:\001*' + _globals['_AUTHORIZERADMINSERVICE'].methods_by_name['FgaDeleteTuples']._loaded_options = None + _globals['_AUTHORIZERADMINSERVICE'].methods_by_name['FgaDeleteTuples']._serialized_options = b'\202\323\344\223\002 \"\033/v1/admin/fga/tuples/delete:\001*' + _globals['_AUTHORIZERADMINSERVICE'].methods_by_name['FgaReadTuples']._loaded_options = None + _globals['_AUTHORIZERADMINSERVICE'].methods_by_name['FgaReadTuples']._serialized_options = b'\202\323\344\223\002\036\"\031/v1/admin/fga/tuples/read:\001*' + _globals['_AUTHORIZERADMINSERVICE'].methods_by_name['FgaListUsers']._loaded_options = None + _globals['_AUTHORIZERADMINSERVICE'].methods_by_name['FgaListUsers']._serialized_options = b'\202\323\344\223\002\035\"\030/v1/admin/fga/list_users:\001*' + _globals['_AUTHORIZERADMINSERVICE'].methods_by_name['FgaExpand']._loaded_options = None + _globals['_AUTHORIZERADMINSERVICE'].methods_by_name['FgaExpand']._serialized_options = b'\202\323\344\223\002\031\"\024/v1/admin/fga/expand:\001*' + _globals['_AUTHORIZERADMINSERVICE'].methods_by_name['FgaReset']._loaded_options = None + _globals['_AUTHORIZERADMINSERVICE'].methods_by_name['FgaReset']._serialized_options = b'\202\323\344\223\002\030\"\023/v1/admin/fga/reset:\001*' + _globals['_ADMINLOGINREQUEST']._serialized_start=223 + _globals['_ADMINLOGINREQUEST']._serialized_end=286 + _globals['_ADMINLOGINRESPONSE']._serialized_start=288 + _globals['_ADMINLOGINRESPONSE']._serialized_end=334 + _globals['_ADMINLOGOUTREQUEST']._serialized_start=336 + _globals['_ADMINLOGOUTREQUEST']._serialized_end=356 + _globals['_ADMINLOGOUTRESPONSE']._serialized_start=358 + _globals['_ADMINLOGOUTRESPONSE']._serialized_end=405 + _globals['_ADMINSESSIONREQUEST']._serialized_start=407 + _globals['_ADMINSESSIONREQUEST']._serialized_end=428 + _globals['_ADMINSESSIONRESPONSE']._serialized_start=430 + _globals['_ADMINSESSIONRESPONSE']._serialized_end=478 + _globals['_ADMINMETAREQUEST']._serialized_start=480 + _globals['_ADMINMETAREQUEST']._serialized_end=498 + _globals['_ADMINMETARESPONSE']._serialized_start=500 + _globals['_ADMINMETARESPONSE']._serialized_end=576 + _globals['_ADMINMETA']._serialized_start=578 + _globals['_ADMINMETA']._serialized_end=689 + _globals['_USERSREQUEST']._serialized_start=691 + _globals['_USERSREQUEST']._serialized_end=771 + _globals['_USERSRESPONSE']._serialized_start=773 + _globals['_USERSRESPONSE']._serialized_end=890 + _globals['_USERREQUEST']._serialized_start=892 + _globals['_USERREQUEST']._serialized_end=943 + _globals['_USERRESPONSE']._serialized_start=945 + _globals['_USERRESPONSE']._serialized_end=1000 + _globals['_UPDATEUSERREQUEST']._serialized_start=1003 + _globals['_UPDATEUSERREQUEST']._serialized_end=1799 + _globals['_UPDATEUSERRESPONSE']._serialized_start=1801 + _globals['_UPDATEUSERRESPONSE']._serialized_end=1862 + _globals['_DELETEUSERREQUEST']._serialized_start=1864 + _globals['_DELETEUSERREQUEST']._serialized_end=1914 + _globals['_DELETEUSERRESPONSE']._serialized_start=1916 + _globals['_DELETEUSERRESPONSE']._serialized_end=1962 + _globals['_VERIFICATIONREQUESTSREQUEST']._serialized_start=1964 + _globals['_VERIFICATIONREQUESTSREQUEST']._serialized_end=2059 + _globals['_VERIFICATIONREQUESTSRESPONSE']._serialized_start=2062 + _globals['_VERIFICATIONREQUESTSRESPONSE']._serialized_end=2240 + _globals['_VERIFICATIONREQUEST']._serialized_start=2243 + _globals['_VERIFICATIONREQUEST']._serialized_end=2501 + _globals['_REVOKEACCESSREQUEST']._serialized_start=2503 + _globals['_REVOKEACCESSREQUEST']._serialized_end=2558 + _globals['_REVOKEACCESSRESPONSE']._serialized_start=2560 + _globals['_REVOKEACCESSRESPONSE']._serialized_end=2608 + _globals['_ENABLEACCESSREQUEST']._serialized_start=2610 + _globals['_ENABLEACCESSREQUEST']._serialized_end=2665 + _globals['_ENABLEACCESSRESPONSE']._serialized_start=2667 + _globals['_ENABLEACCESSRESPONSE']._serialized_end=2715 + _globals['_INVITEMEMBERSREQUEST']._serialized_start=2717 + _globals['_INVITEMEMBERSREQUEST']._serialized_end=2820 + _globals['_INVITEMEMBERSRESPONSE']._serialized_start=2822 + _globals['_INVITEMEMBERSRESPONSE']._serialized_end=2914 + _globals['_WEBHOOK']._serialized_start=2917 + _globals['_WEBHOOK']._serialized_end=3184 + _globals['_WEBHOOKLOG']._serialized_start=3187 + _globals['_WEBHOOKLOG']._serialized_end=3395 + _globals['_ADDWEBHOOKREQUEST']._serialized_start=3398 + _globals['_ADDWEBHOOKREQUEST']._serialized_end=3642 + _globals['_ADDWEBHOOKRESPONSE']._serialized_start=3644 + _globals['_ADDWEBHOOKRESPONSE']._serialized_end=3690 + _globals['_UPDATEWEBHOOKREQUEST']._serialized_start=3693 + _globals['_UPDATEWEBHOOKREQUEST']._serialized_end=4002 + _globals['_UPDATEWEBHOOKRESPONSE']._serialized_start=4004 + _globals['_UPDATEWEBHOOKRESPONSE']._serialized_end=4053 + _globals['_DELETEWEBHOOKREQUEST']._serialized_start=4055 + _globals['_DELETEWEBHOOKREQUEST']._serialized_end=4102 + _globals['_DELETEWEBHOOKRESPONSE']._serialized_start=4104 + _globals['_DELETEWEBHOOKRESPONSE']._serialized_end=4153 + _globals['_GETWEBHOOKREQUEST']._serialized_start=4155 + _globals['_GETWEBHOOKREQUEST']._serialized_end=4199 + _globals['_GETWEBHOOKRESPONSE']._serialized_start=4201 + _globals['_GETWEBHOOKRESPONSE']._serialized_end=4271 + _globals['_WEBHOOKSREQUEST']._serialized_start=4273 + _globals['_WEBHOOKSREQUEST']._serialized_end=4356 + _globals['_WEBHOOKSRESPONSE']._serialized_start=4359 + _globals['_WEBHOOKSRESPONSE']._serialized_end=4488 + _globals['_WEBHOOKLOGSREQUEST']._serialized_start=4491 + _globals['_WEBHOOKLOGSREQUEST']._serialized_end=4628 + _globals['_WEBHOOKLOGSRESPONSE']._serialized_start=4631 + _globals['_WEBHOOKLOGSRESPONSE']._serialized_end=4773 + _globals['_TESTENDPOINTREQUEST']._serialized_start=4776 + _globals['_TESTENDPOINTREQUEST']._serialized_end=4996 + _globals['_TESTENDPOINTRESPONSE']._serialized_start=4998 + _globals['_TESTENDPOINTRESPONSE']._serialized_end=5081 + _globals['_EMAILTEMPLATE']._serialized_start=5084 + _globals['_EMAILTEMPLATE']._serialized_end=5286 + _globals['_ADDEMAILTEMPLATEREQUEST']._serialized_start=5289 + _globals['_ADDEMAILTEMPLATEREQUEST']._serialized_end=5466 + _globals['_ADDEMAILTEMPLATERESPONSE']._serialized_start=5468 + _globals['_ADDEMAILTEMPLATERESPONSE']._serialized_end=5520 + _globals['_UPDATEEMAILTEMPLATEREQUEST']._serialized_start=5523 + _globals['_UPDATEEMAILTEMPLATEREQUEST']._serialized_end=5756 + _globals['_UPDATEEMAILTEMPLATERESPONSE']._serialized_start=5758 + _globals['_UPDATEEMAILTEMPLATERESPONSE']._serialized_end=5813 + _globals['_DELETEEMAILTEMPLATEREQUEST']._serialized_start=5815 + _globals['_DELETEEMAILTEMPLATEREQUEST']._serialized_end=5868 + _globals['_DELETEEMAILTEMPLATERESPONSE']._serialized_start=5870 + _globals['_DELETEEMAILTEMPLATERESPONSE']._serialized_end=5925 + _globals['_EMAILTEMPLATESREQUEST']._serialized_start=5927 + _globals['_EMAILTEMPLATESREQUEST']._serialized_end=6016 + _globals['_EMAILTEMPLATESRESPONSE']._serialized_start=6019 + _globals['_EMAILTEMPLATESRESPONSE']._serialized_end=6173 + _globals['_AUDITLOG']._serialized_start=6176 + _globals['_AUDITLOG']._serialized_end=6508 + _globals['_AUDITLOGSREQUEST']._serialized_start=6511 + _globals['_AUDITLOGSREQUEST']._serialized_end=6914 + _globals['_AUDITLOGSRESPONSE']._serialized_start=6917 + _globals['_AUDITLOGSRESPONSE']._serialized_end=7051 + _globals['_FGAMODEL']._serialized_start=7053 + _globals['_FGAMODEL']._serialized_end=7097 + _globals['_FGATUPLE']._serialized_start=7099 + _globals['_FGATUPLE']._serialized_end=7181 + _globals['_FGAGETMODELREQUEST']._serialized_start=7183 + _globals['_FGAGETMODELREQUEST']._serialized_end=7203 + _globals['_FGAGETMODELRESPONSE']._serialized_start=7205 + _globals['_FGAGETMODELRESPONSE']._serialized_end=7273 + _globals['_FGAWRITEMODELREQUEST']._serialized_start=7275 + _globals['_FGAWRITEMODELREQUEST']._serialized_end=7324 + _globals['_FGAWRITEMODELRESPONSE']._serialized_start=7326 + _globals['_FGAWRITEMODELRESPONSE']._serialized_end=7396 + _globals['_FGAWRITETUPLESREQUEST']._serialized_start=7398 + _globals['_FGAWRITETUPLESREQUEST']._serialized_end=7475 + _globals['_FGAWRITETUPLESRESPONSE']._serialized_start=7477 + _globals['_FGAWRITETUPLESRESPONSE']._serialized_end=7527 + _globals['_FGADELETETUPLESREQUEST']._serialized_start=7529 + _globals['_FGADELETETUPLESREQUEST']._serialized_end=7607 + _globals['_FGADELETETUPLESRESPONSE']._serialized_start=7609 + _globals['_FGADELETETUPLESRESPONSE']._serialized_end=7660 + _globals['_FGAREADTUPLESREQUEST']._serialized_start=7663 + _globals['_FGAREADTUPLESREQUEST']._serialized_end=7928 + _globals['_FGAREADTUPLESRESPONSE']._serialized_start=7931 + _globals['_FGAREADTUPLESRESPONSE']._serialized_end=8078 + _globals['_FGALISTUSERSREQUEST']._serialized_start=8081 + _globals['_FGALISTUSERSREQUEST']._serialized_end=8210 + _globals['_FGALISTUSERSRESPONSE']._serialized_start=8212 + _globals['_FGALISTUSERSRESPONSE']._serialized_end=8256 + _globals['_FGAEXPANDREQUEST']._serialized_start=8258 + _globals['_FGAEXPANDREQUEST']._serialized_end=8346 + _globals['_FGAEXPANDRESPONSE']._serialized_start=8348 + _globals['_FGAEXPANDRESPONSE']._serialized_end=8387 + _globals['_FGARESETREQUEST']._serialized_start=8389 + _globals['_FGARESETREQUEST']._serialized_end=8406 + _globals['_FGARESETRESPONSE']._serialized_start=8408 + _globals['_FGARESETRESPONSE']._serialized_end=8452 + _globals['_AUTHORIZERADMINSERVICE']._serialized_start=8455 + _globals['_AUTHORIZERADMINSERVICE']._serialized_end=12412 +# @@protoc_insertion_point(module_scope) diff --git a/src/authorizer/_grpc/authorizer/v1/admin_pb2_grpc.py b/src/authorizer/_grpc/authorizer/v1/admin_pb2_grpc.py new file mode 100644 index 0000000..3e82b6e --- /dev/null +++ b/src/authorizer/_grpc/authorizer/v1/admin_pb2_grpc.py @@ -0,0 +1,1501 @@ +# Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT! +"""Client and server classes corresponding to protobuf-defined services.""" +import grpc + +from authorizer._grpc.authorizer.v1 import admin_pb2 as authorizer_dot_v1_dot_admin__pb2 + + +class AuthorizerAdminServiceStub(object): + """AuthorizerAdminService is the single gRPC service for Authorizer's admin + (super-admin-only) API surface. RPCs are added one domain group at a time; + see specs/2026-06-15-authorizer-admin-service-plan.md. + === Admin auth + meta === + """ + + def __init__(self, channel): + """Constructor. + + Args: + channel: A grpc.Channel. + """ + self.AdminLogin = channel.unary_unary( + '/authorizer.v1.AuthorizerAdminService/AdminLogin', + request_serializer=authorizer_dot_v1_dot_admin__pb2.AdminLoginRequest.SerializeToString, + response_deserializer=authorizer_dot_v1_dot_admin__pb2.AdminLoginResponse.FromString, + _registered_method=True) + self.AdminLogout = channel.unary_unary( + '/authorizer.v1.AuthorizerAdminService/AdminLogout', + request_serializer=authorizer_dot_v1_dot_admin__pb2.AdminLogoutRequest.SerializeToString, + response_deserializer=authorizer_dot_v1_dot_admin__pb2.AdminLogoutResponse.FromString, + _registered_method=True) + self.AdminSession = channel.unary_unary( + '/authorizer.v1.AuthorizerAdminService/AdminSession', + request_serializer=authorizer_dot_v1_dot_admin__pb2.AdminSessionRequest.SerializeToString, + response_deserializer=authorizer_dot_v1_dot_admin__pb2.AdminSessionResponse.FromString, + _registered_method=True) + self.AdminMeta = channel.unary_unary( + '/authorizer.v1.AuthorizerAdminService/AdminMeta', + request_serializer=authorizer_dot_v1_dot_admin__pb2.AdminMetaRequest.SerializeToString, + response_deserializer=authorizer_dot_v1_dot_admin__pb2.AdminMetaResponse.FromString, + _registered_method=True) + self.Users = channel.unary_unary( + '/authorizer.v1.AuthorizerAdminService/Users', + request_serializer=authorizer_dot_v1_dot_admin__pb2.UsersRequest.SerializeToString, + response_deserializer=authorizer_dot_v1_dot_admin__pb2.UsersResponse.FromString, + _registered_method=True) + self.User = channel.unary_unary( + '/authorizer.v1.AuthorizerAdminService/User', + request_serializer=authorizer_dot_v1_dot_admin__pb2.UserRequest.SerializeToString, + response_deserializer=authorizer_dot_v1_dot_admin__pb2.UserResponse.FromString, + _registered_method=True) + self.UpdateUser = channel.unary_unary( + '/authorizer.v1.AuthorizerAdminService/UpdateUser', + request_serializer=authorizer_dot_v1_dot_admin__pb2.UpdateUserRequest.SerializeToString, + response_deserializer=authorizer_dot_v1_dot_admin__pb2.UpdateUserResponse.FromString, + _registered_method=True) + self.DeleteUser = channel.unary_unary( + '/authorizer.v1.AuthorizerAdminService/DeleteUser', + request_serializer=authorizer_dot_v1_dot_admin__pb2.DeleteUserRequest.SerializeToString, + response_deserializer=authorizer_dot_v1_dot_admin__pb2.DeleteUserResponse.FromString, + _registered_method=True) + self.VerificationRequests = channel.unary_unary( + '/authorizer.v1.AuthorizerAdminService/VerificationRequests', + request_serializer=authorizer_dot_v1_dot_admin__pb2.VerificationRequestsRequest.SerializeToString, + response_deserializer=authorizer_dot_v1_dot_admin__pb2.VerificationRequestsResponse.FromString, + _registered_method=True) + self.RevokeAccess = channel.unary_unary( + '/authorizer.v1.AuthorizerAdminService/RevokeAccess', + request_serializer=authorizer_dot_v1_dot_admin__pb2.RevokeAccessRequest.SerializeToString, + response_deserializer=authorizer_dot_v1_dot_admin__pb2.RevokeAccessResponse.FromString, + _registered_method=True) + self.EnableAccess = channel.unary_unary( + '/authorizer.v1.AuthorizerAdminService/EnableAccess', + request_serializer=authorizer_dot_v1_dot_admin__pb2.EnableAccessRequest.SerializeToString, + response_deserializer=authorizer_dot_v1_dot_admin__pb2.EnableAccessResponse.FromString, + _registered_method=True) + self.InviteMembers = channel.unary_unary( + '/authorizer.v1.AuthorizerAdminService/InviteMembers', + request_serializer=authorizer_dot_v1_dot_admin__pb2.InviteMembersRequest.SerializeToString, + response_deserializer=authorizer_dot_v1_dot_admin__pb2.InviteMembersResponse.FromString, + _registered_method=True) + self.AddWebhook = channel.unary_unary( + '/authorizer.v1.AuthorizerAdminService/AddWebhook', + request_serializer=authorizer_dot_v1_dot_admin__pb2.AddWebhookRequest.SerializeToString, + response_deserializer=authorizer_dot_v1_dot_admin__pb2.AddWebhookResponse.FromString, + _registered_method=True) + self.UpdateWebhook = channel.unary_unary( + '/authorizer.v1.AuthorizerAdminService/UpdateWebhook', + request_serializer=authorizer_dot_v1_dot_admin__pb2.UpdateWebhookRequest.SerializeToString, + response_deserializer=authorizer_dot_v1_dot_admin__pb2.UpdateWebhookResponse.FromString, + _registered_method=True) + self.DeleteWebhook = channel.unary_unary( + '/authorizer.v1.AuthorizerAdminService/DeleteWebhook', + request_serializer=authorizer_dot_v1_dot_admin__pb2.DeleteWebhookRequest.SerializeToString, + response_deserializer=authorizer_dot_v1_dot_admin__pb2.DeleteWebhookResponse.FromString, + _registered_method=True) + self.GetWebhook = channel.unary_unary( + '/authorizer.v1.AuthorizerAdminService/GetWebhook', + request_serializer=authorizer_dot_v1_dot_admin__pb2.GetWebhookRequest.SerializeToString, + response_deserializer=authorizer_dot_v1_dot_admin__pb2.GetWebhookResponse.FromString, + _registered_method=True) + self.Webhooks = channel.unary_unary( + '/authorizer.v1.AuthorizerAdminService/Webhooks', + request_serializer=authorizer_dot_v1_dot_admin__pb2.WebhooksRequest.SerializeToString, + response_deserializer=authorizer_dot_v1_dot_admin__pb2.WebhooksResponse.FromString, + _registered_method=True) + self.WebhookLogs = channel.unary_unary( + '/authorizer.v1.AuthorizerAdminService/WebhookLogs', + request_serializer=authorizer_dot_v1_dot_admin__pb2.WebhookLogsRequest.SerializeToString, + response_deserializer=authorizer_dot_v1_dot_admin__pb2.WebhookLogsResponse.FromString, + _registered_method=True) + self.TestEndpoint = channel.unary_unary( + '/authorizer.v1.AuthorizerAdminService/TestEndpoint', + request_serializer=authorizer_dot_v1_dot_admin__pb2.TestEndpointRequest.SerializeToString, + response_deserializer=authorizer_dot_v1_dot_admin__pb2.TestEndpointResponse.FromString, + _registered_method=True) + self.AddEmailTemplate = channel.unary_unary( + '/authorizer.v1.AuthorizerAdminService/AddEmailTemplate', + request_serializer=authorizer_dot_v1_dot_admin__pb2.AddEmailTemplateRequest.SerializeToString, + response_deserializer=authorizer_dot_v1_dot_admin__pb2.AddEmailTemplateResponse.FromString, + _registered_method=True) + self.UpdateEmailTemplate = channel.unary_unary( + '/authorizer.v1.AuthorizerAdminService/UpdateEmailTemplate', + request_serializer=authorizer_dot_v1_dot_admin__pb2.UpdateEmailTemplateRequest.SerializeToString, + response_deserializer=authorizer_dot_v1_dot_admin__pb2.UpdateEmailTemplateResponse.FromString, + _registered_method=True) + self.DeleteEmailTemplate = channel.unary_unary( + '/authorizer.v1.AuthorizerAdminService/DeleteEmailTemplate', + request_serializer=authorizer_dot_v1_dot_admin__pb2.DeleteEmailTemplateRequest.SerializeToString, + response_deserializer=authorizer_dot_v1_dot_admin__pb2.DeleteEmailTemplateResponse.FromString, + _registered_method=True) + self.EmailTemplates = channel.unary_unary( + '/authorizer.v1.AuthorizerAdminService/EmailTemplates', + request_serializer=authorizer_dot_v1_dot_admin__pb2.EmailTemplatesRequest.SerializeToString, + response_deserializer=authorizer_dot_v1_dot_admin__pb2.EmailTemplatesResponse.FromString, + _registered_method=True) + self.AuditLogs = channel.unary_unary( + '/authorizer.v1.AuthorizerAdminService/AuditLogs', + request_serializer=authorizer_dot_v1_dot_admin__pb2.AuditLogsRequest.SerializeToString, + response_deserializer=authorizer_dot_v1_dot_admin__pb2.AuditLogsResponse.FromString, + _registered_method=True) + self.FgaGetModel = channel.unary_unary( + '/authorizer.v1.AuthorizerAdminService/FgaGetModel', + request_serializer=authorizer_dot_v1_dot_admin__pb2.FgaGetModelRequest.SerializeToString, + response_deserializer=authorizer_dot_v1_dot_admin__pb2.FgaGetModelResponse.FromString, + _registered_method=True) + self.FgaWriteModel = channel.unary_unary( + '/authorizer.v1.AuthorizerAdminService/FgaWriteModel', + request_serializer=authorizer_dot_v1_dot_admin__pb2.FgaWriteModelRequest.SerializeToString, + response_deserializer=authorizer_dot_v1_dot_admin__pb2.FgaWriteModelResponse.FromString, + _registered_method=True) + self.FgaWriteTuples = channel.unary_unary( + '/authorizer.v1.AuthorizerAdminService/FgaWriteTuples', + request_serializer=authorizer_dot_v1_dot_admin__pb2.FgaWriteTuplesRequest.SerializeToString, + response_deserializer=authorizer_dot_v1_dot_admin__pb2.FgaWriteTuplesResponse.FromString, + _registered_method=True) + self.FgaDeleteTuples = channel.unary_unary( + '/authorizer.v1.AuthorizerAdminService/FgaDeleteTuples', + request_serializer=authorizer_dot_v1_dot_admin__pb2.FgaDeleteTuplesRequest.SerializeToString, + response_deserializer=authorizer_dot_v1_dot_admin__pb2.FgaDeleteTuplesResponse.FromString, + _registered_method=True) + self.FgaReadTuples = channel.unary_unary( + '/authorizer.v1.AuthorizerAdminService/FgaReadTuples', + request_serializer=authorizer_dot_v1_dot_admin__pb2.FgaReadTuplesRequest.SerializeToString, + response_deserializer=authorizer_dot_v1_dot_admin__pb2.FgaReadTuplesResponse.FromString, + _registered_method=True) + self.FgaListUsers = channel.unary_unary( + '/authorizer.v1.AuthorizerAdminService/FgaListUsers', + request_serializer=authorizer_dot_v1_dot_admin__pb2.FgaListUsersRequest.SerializeToString, + response_deserializer=authorizer_dot_v1_dot_admin__pb2.FgaListUsersResponse.FromString, + _registered_method=True) + self.FgaExpand = channel.unary_unary( + '/authorizer.v1.AuthorizerAdminService/FgaExpand', + request_serializer=authorizer_dot_v1_dot_admin__pb2.FgaExpandRequest.SerializeToString, + response_deserializer=authorizer_dot_v1_dot_admin__pb2.FgaExpandResponse.FromString, + _registered_method=True) + self.FgaReset = channel.unary_unary( + '/authorizer.v1.AuthorizerAdminService/FgaReset', + request_serializer=authorizer_dot_v1_dot_admin__pb2.FgaResetRequest.SerializeToString, + response_deserializer=authorizer_dot_v1_dot_admin__pb2.FgaResetResponse.FromString, + _registered_method=True) + + +class AuthorizerAdminServiceServicer(object): + """AuthorizerAdminService is the single gRPC service for Authorizer's admin + (super-admin-only) API surface. RPCs are added one domain group at a time; + see specs/2026-06-15-authorizer-admin-service-plan.md. + === Admin auth + meta === + """ + + def AdminLogin(self, request, context): + """AdminLogin validates the admin secret and establishes an admin session + (Set-Cookie for browser callers). Public entry point — the ONLY admin RPC + that does not require an existing super-admin session. + """ + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + def AdminLogout(self, request, context): + """AdminLogout clears the admin session cookie. Requires super-admin auth. + """ + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + def AdminSession(self, request, context): + """AdminSession refreshes the admin session cookie. Requires super-admin auth. + """ + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + def AdminMeta(self, request, context): + """AdminMeta returns admin-only configuration metadata (configured roles, + default roles, protected roles). Requires super-admin auth. + """ + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + def Users(self, request, context): + """=== Users === + + Users returns a paginated list of all users. Requires super-admin auth. + """ + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + def User(self, request, context): + """User returns a single user by id or email. Requires super-admin auth. + """ + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + def UpdateUser(self, request, context): + """UpdateUser updates a user's profile, roles, MFA, or verification state and + returns the updated user. Requires super-admin auth. + """ + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + def DeleteUser(self, request, context): + """DeleteUser deletes a user (and associated OTP/verification data) by email. + Requires super-admin auth. + """ + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + def VerificationRequests(self, request, context): + """VerificationRequests returns a paginated list of pending verification + requests. Requires super-admin auth. + """ + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + def RevokeAccess(self, request, context): + """=== Access === + + RevokeAccess revokes a user's access (sets the revoked timestamp), kills + their sessions, and fires the access-revoked webhook. Requires super-admin + auth. + """ + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + def EnableAccess(self, request, context): + """EnableAccess re-enables a previously revoked user (clears the revoked + timestamp) and fires the access-enabled webhook. Requires super-admin auth. + """ + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + def InviteMembers(self, request, context): + """InviteMembers creates accounts for new emails and sends invite emails. + Requires super-admin auth and a configured email service. + """ + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + def AddWebhook(self, request, context): + """=== Webhooks === + + AddWebhook registers a new webhook for an event. Requires super-admin auth. + """ + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + def UpdateWebhook(self, request, context): + """UpdateWebhook updates an existing webhook's event, endpoint, headers, or + enabled state. Requires super-admin auth. + """ + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + def DeleteWebhook(self, request, context): + """DeleteWebhook deletes a webhook by id. Requires super-admin auth. + """ + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + def GetWebhook(self, request, context): + """GetWebhook returns a single webhook by id. Requires super-admin auth. + """ + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + def Webhooks(self, request, context): + """Webhooks returns a paginated list of webhooks. Requires super-admin auth. + """ + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + def WebhookLogs(self, request, context): + """WebhookLogs returns a paginated list of webhook delivery logs, optionally + filtered by webhook id. Requires super-admin auth. + """ + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + def TestEndpoint(self, request, context): + """TestEndpoint sends a synthetic event payload to a webhook endpoint and + returns the HTTP status and response body. Requires super-admin auth. + """ + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + def AddEmailTemplate(self, request, context): + """=== Email templates === + + AddEmailTemplate creates a new email template for an event. Requires + super-admin auth. + """ + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + def UpdateEmailTemplate(self, request, context): + """UpdateEmailTemplate updates an existing email template's event, subject, + body, or design. Requires super-admin auth. + """ + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + def DeleteEmailTemplate(self, request, context): + """DeleteEmailTemplate deletes an email template by id. Requires super-admin + auth. + """ + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + def EmailTemplates(self, request, context): + """EmailTemplates returns a paginated list of email templates. Requires + super-admin auth. + """ + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + def AuditLogs(self, request, context): + """=== Audit === + + AuditLogs returns a paginated, optionally-filtered list of audit log + entries. Requires super-admin auth. + """ + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + def FgaGetModel(self, request, context): + """=== FGA (fine-grained authorization) admin === + + Every FGA admin RPC fails closed when no authorization engine is configured + (no --fga-store): it returns FailedPrecondition rather than nil-deref or + silently succeeding. Requires super-admin auth. + + FgaGetModel returns the active fine-grained authorization model as DSL. A + store with no model yet returns an empty model (not an error). Requires + super-admin auth. + """ + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + def FgaWriteModel(self, request, context): + """FgaWriteModel installs a new fine-grained authorization model from its DSL + and returns the new model id. Requires super-admin auth. Audited. + """ + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + def FgaWriteTuples(self, request, context): + """FgaWriteTuples persists the given relationship tuples (additive). Requires + super-admin auth. Audited. + """ + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + def FgaDeleteTuples(self, request, context): + """FgaDeleteTuples removes the given relationship tuples. Requires super-admin + auth. Audited. + """ + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + def FgaReadTuples(self, request, context): + """FgaReadTuples returns a page of persisted tuples matching the filter. + Requires super-admin auth. + """ + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + def FgaListUsers(self, request, context): + """FgaListUsers returns the fully-qualified user ids of user_type that have + relation on object ("who can access this object?"). Requires super-admin + auth. + """ + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + def FgaExpand(self, request, context): + """FgaExpand returns the OpenFGA relationship/userset tree for (relation, + object) as a JSON string (the explainability primitive). Requires + super-admin auth. + """ + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + def FgaReset(self, request, context): + """FgaReset deletes the entire fine-grained authorization store (the model, + all its versions, and all tuples) and starts a fresh, empty store. Refused + while any tuples still exist. Requires super-admin auth. Destructive and + audited. + """ + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + +def add_AuthorizerAdminServiceServicer_to_server(servicer, server): + rpc_method_handlers = { + 'AdminLogin': grpc.unary_unary_rpc_method_handler( + servicer.AdminLogin, + request_deserializer=authorizer_dot_v1_dot_admin__pb2.AdminLoginRequest.FromString, + response_serializer=authorizer_dot_v1_dot_admin__pb2.AdminLoginResponse.SerializeToString, + ), + 'AdminLogout': grpc.unary_unary_rpc_method_handler( + servicer.AdminLogout, + request_deserializer=authorizer_dot_v1_dot_admin__pb2.AdminLogoutRequest.FromString, + response_serializer=authorizer_dot_v1_dot_admin__pb2.AdminLogoutResponse.SerializeToString, + ), + 'AdminSession': grpc.unary_unary_rpc_method_handler( + servicer.AdminSession, + request_deserializer=authorizer_dot_v1_dot_admin__pb2.AdminSessionRequest.FromString, + response_serializer=authorizer_dot_v1_dot_admin__pb2.AdminSessionResponse.SerializeToString, + ), + 'AdminMeta': grpc.unary_unary_rpc_method_handler( + servicer.AdminMeta, + request_deserializer=authorizer_dot_v1_dot_admin__pb2.AdminMetaRequest.FromString, + response_serializer=authorizer_dot_v1_dot_admin__pb2.AdminMetaResponse.SerializeToString, + ), + 'Users': grpc.unary_unary_rpc_method_handler( + servicer.Users, + request_deserializer=authorizer_dot_v1_dot_admin__pb2.UsersRequest.FromString, + response_serializer=authorizer_dot_v1_dot_admin__pb2.UsersResponse.SerializeToString, + ), + 'User': grpc.unary_unary_rpc_method_handler( + servicer.User, + request_deserializer=authorizer_dot_v1_dot_admin__pb2.UserRequest.FromString, + response_serializer=authorizer_dot_v1_dot_admin__pb2.UserResponse.SerializeToString, + ), + 'UpdateUser': grpc.unary_unary_rpc_method_handler( + servicer.UpdateUser, + request_deserializer=authorizer_dot_v1_dot_admin__pb2.UpdateUserRequest.FromString, + response_serializer=authorizer_dot_v1_dot_admin__pb2.UpdateUserResponse.SerializeToString, + ), + 'DeleteUser': grpc.unary_unary_rpc_method_handler( + servicer.DeleteUser, + request_deserializer=authorizer_dot_v1_dot_admin__pb2.DeleteUserRequest.FromString, + response_serializer=authorizer_dot_v1_dot_admin__pb2.DeleteUserResponse.SerializeToString, + ), + 'VerificationRequests': grpc.unary_unary_rpc_method_handler( + servicer.VerificationRequests, + request_deserializer=authorizer_dot_v1_dot_admin__pb2.VerificationRequestsRequest.FromString, + response_serializer=authorizer_dot_v1_dot_admin__pb2.VerificationRequestsResponse.SerializeToString, + ), + 'RevokeAccess': grpc.unary_unary_rpc_method_handler( + servicer.RevokeAccess, + request_deserializer=authorizer_dot_v1_dot_admin__pb2.RevokeAccessRequest.FromString, + response_serializer=authorizer_dot_v1_dot_admin__pb2.RevokeAccessResponse.SerializeToString, + ), + 'EnableAccess': grpc.unary_unary_rpc_method_handler( + servicer.EnableAccess, + request_deserializer=authorizer_dot_v1_dot_admin__pb2.EnableAccessRequest.FromString, + response_serializer=authorizer_dot_v1_dot_admin__pb2.EnableAccessResponse.SerializeToString, + ), + 'InviteMembers': grpc.unary_unary_rpc_method_handler( + servicer.InviteMembers, + request_deserializer=authorizer_dot_v1_dot_admin__pb2.InviteMembersRequest.FromString, + response_serializer=authorizer_dot_v1_dot_admin__pb2.InviteMembersResponse.SerializeToString, + ), + 'AddWebhook': grpc.unary_unary_rpc_method_handler( + servicer.AddWebhook, + request_deserializer=authorizer_dot_v1_dot_admin__pb2.AddWebhookRequest.FromString, + response_serializer=authorizer_dot_v1_dot_admin__pb2.AddWebhookResponse.SerializeToString, + ), + 'UpdateWebhook': grpc.unary_unary_rpc_method_handler( + servicer.UpdateWebhook, + request_deserializer=authorizer_dot_v1_dot_admin__pb2.UpdateWebhookRequest.FromString, + response_serializer=authorizer_dot_v1_dot_admin__pb2.UpdateWebhookResponse.SerializeToString, + ), + 'DeleteWebhook': grpc.unary_unary_rpc_method_handler( + servicer.DeleteWebhook, + request_deserializer=authorizer_dot_v1_dot_admin__pb2.DeleteWebhookRequest.FromString, + response_serializer=authorizer_dot_v1_dot_admin__pb2.DeleteWebhookResponse.SerializeToString, + ), + 'GetWebhook': grpc.unary_unary_rpc_method_handler( + servicer.GetWebhook, + request_deserializer=authorizer_dot_v1_dot_admin__pb2.GetWebhookRequest.FromString, + response_serializer=authorizer_dot_v1_dot_admin__pb2.GetWebhookResponse.SerializeToString, + ), + 'Webhooks': grpc.unary_unary_rpc_method_handler( + servicer.Webhooks, + request_deserializer=authorizer_dot_v1_dot_admin__pb2.WebhooksRequest.FromString, + response_serializer=authorizer_dot_v1_dot_admin__pb2.WebhooksResponse.SerializeToString, + ), + 'WebhookLogs': grpc.unary_unary_rpc_method_handler( + servicer.WebhookLogs, + request_deserializer=authorizer_dot_v1_dot_admin__pb2.WebhookLogsRequest.FromString, + response_serializer=authorizer_dot_v1_dot_admin__pb2.WebhookLogsResponse.SerializeToString, + ), + 'TestEndpoint': grpc.unary_unary_rpc_method_handler( + servicer.TestEndpoint, + request_deserializer=authorizer_dot_v1_dot_admin__pb2.TestEndpointRequest.FromString, + response_serializer=authorizer_dot_v1_dot_admin__pb2.TestEndpointResponse.SerializeToString, + ), + 'AddEmailTemplate': grpc.unary_unary_rpc_method_handler( + servicer.AddEmailTemplate, + request_deserializer=authorizer_dot_v1_dot_admin__pb2.AddEmailTemplateRequest.FromString, + response_serializer=authorizer_dot_v1_dot_admin__pb2.AddEmailTemplateResponse.SerializeToString, + ), + 'UpdateEmailTemplate': grpc.unary_unary_rpc_method_handler( + servicer.UpdateEmailTemplate, + request_deserializer=authorizer_dot_v1_dot_admin__pb2.UpdateEmailTemplateRequest.FromString, + response_serializer=authorizer_dot_v1_dot_admin__pb2.UpdateEmailTemplateResponse.SerializeToString, + ), + 'DeleteEmailTemplate': grpc.unary_unary_rpc_method_handler( + servicer.DeleteEmailTemplate, + request_deserializer=authorizer_dot_v1_dot_admin__pb2.DeleteEmailTemplateRequest.FromString, + response_serializer=authorizer_dot_v1_dot_admin__pb2.DeleteEmailTemplateResponse.SerializeToString, + ), + 'EmailTemplates': grpc.unary_unary_rpc_method_handler( + servicer.EmailTemplates, + request_deserializer=authorizer_dot_v1_dot_admin__pb2.EmailTemplatesRequest.FromString, + response_serializer=authorizer_dot_v1_dot_admin__pb2.EmailTemplatesResponse.SerializeToString, + ), + 'AuditLogs': grpc.unary_unary_rpc_method_handler( + servicer.AuditLogs, + request_deserializer=authorizer_dot_v1_dot_admin__pb2.AuditLogsRequest.FromString, + response_serializer=authorizer_dot_v1_dot_admin__pb2.AuditLogsResponse.SerializeToString, + ), + 'FgaGetModel': grpc.unary_unary_rpc_method_handler( + servicer.FgaGetModel, + request_deserializer=authorizer_dot_v1_dot_admin__pb2.FgaGetModelRequest.FromString, + response_serializer=authorizer_dot_v1_dot_admin__pb2.FgaGetModelResponse.SerializeToString, + ), + 'FgaWriteModel': grpc.unary_unary_rpc_method_handler( + servicer.FgaWriteModel, + request_deserializer=authorizer_dot_v1_dot_admin__pb2.FgaWriteModelRequest.FromString, + response_serializer=authorizer_dot_v1_dot_admin__pb2.FgaWriteModelResponse.SerializeToString, + ), + 'FgaWriteTuples': grpc.unary_unary_rpc_method_handler( + servicer.FgaWriteTuples, + request_deserializer=authorizer_dot_v1_dot_admin__pb2.FgaWriteTuplesRequest.FromString, + response_serializer=authorizer_dot_v1_dot_admin__pb2.FgaWriteTuplesResponse.SerializeToString, + ), + 'FgaDeleteTuples': grpc.unary_unary_rpc_method_handler( + servicer.FgaDeleteTuples, + request_deserializer=authorizer_dot_v1_dot_admin__pb2.FgaDeleteTuplesRequest.FromString, + response_serializer=authorizer_dot_v1_dot_admin__pb2.FgaDeleteTuplesResponse.SerializeToString, + ), + 'FgaReadTuples': grpc.unary_unary_rpc_method_handler( + servicer.FgaReadTuples, + request_deserializer=authorizer_dot_v1_dot_admin__pb2.FgaReadTuplesRequest.FromString, + response_serializer=authorizer_dot_v1_dot_admin__pb2.FgaReadTuplesResponse.SerializeToString, + ), + 'FgaListUsers': grpc.unary_unary_rpc_method_handler( + servicer.FgaListUsers, + request_deserializer=authorizer_dot_v1_dot_admin__pb2.FgaListUsersRequest.FromString, + response_serializer=authorizer_dot_v1_dot_admin__pb2.FgaListUsersResponse.SerializeToString, + ), + 'FgaExpand': grpc.unary_unary_rpc_method_handler( + servicer.FgaExpand, + request_deserializer=authorizer_dot_v1_dot_admin__pb2.FgaExpandRequest.FromString, + response_serializer=authorizer_dot_v1_dot_admin__pb2.FgaExpandResponse.SerializeToString, + ), + 'FgaReset': grpc.unary_unary_rpc_method_handler( + servicer.FgaReset, + request_deserializer=authorizer_dot_v1_dot_admin__pb2.FgaResetRequest.FromString, + response_serializer=authorizer_dot_v1_dot_admin__pb2.FgaResetResponse.SerializeToString, + ), + } + generic_handler = grpc.method_handlers_generic_handler( + 'authorizer.v1.AuthorizerAdminService', rpc_method_handlers) + server.add_generic_rpc_handlers((generic_handler,)) + server.add_registered_method_handlers('authorizer.v1.AuthorizerAdminService', rpc_method_handlers) + + + # This class is part of an EXPERIMENTAL API. +class AuthorizerAdminService(object): + """AuthorizerAdminService is the single gRPC service for Authorizer's admin + (super-admin-only) API surface. RPCs are added one domain group at a time; + see specs/2026-06-15-authorizer-admin-service-plan.md. + === Admin auth + meta === + """ + + @staticmethod + def AdminLogin(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary( + request, + target, + '/authorizer.v1.AuthorizerAdminService/AdminLogin', + authorizer_dot_v1_dot_admin__pb2.AdminLoginRequest.SerializeToString, + authorizer_dot_v1_dot_admin__pb2.AdminLoginResponse.FromString, + options, + channel_credentials, + insecure, + call_credentials, + compression, + wait_for_ready, + timeout, + metadata, + _registered_method=True) + + @staticmethod + def AdminLogout(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary( + request, + target, + '/authorizer.v1.AuthorizerAdminService/AdminLogout', + authorizer_dot_v1_dot_admin__pb2.AdminLogoutRequest.SerializeToString, + authorizer_dot_v1_dot_admin__pb2.AdminLogoutResponse.FromString, + options, + channel_credentials, + insecure, + call_credentials, + compression, + wait_for_ready, + timeout, + metadata, + _registered_method=True) + + @staticmethod + def AdminSession(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary( + request, + target, + '/authorizer.v1.AuthorizerAdminService/AdminSession', + authorizer_dot_v1_dot_admin__pb2.AdminSessionRequest.SerializeToString, + authorizer_dot_v1_dot_admin__pb2.AdminSessionResponse.FromString, + options, + channel_credentials, + insecure, + call_credentials, + compression, + wait_for_ready, + timeout, + metadata, + _registered_method=True) + + @staticmethod + def AdminMeta(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary( + request, + target, + '/authorizer.v1.AuthorizerAdminService/AdminMeta', + authorizer_dot_v1_dot_admin__pb2.AdminMetaRequest.SerializeToString, + authorizer_dot_v1_dot_admin__pb2.AdminMetaResponse.FromString, + options, + channel_credentials, + insecure, + call_credentials, + compression, + wait_for_ready, + timeout, + metadata, + _registered_method=True) + + @staticmethod + def Users(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary( + request, + target, + '/authorizer.v1.AuthorizerAdminService/Users', + authorizer_dot_v1_dot_admin__pb2.UsersRequest.SerializeToString, + authorizer_dot_v1_dot_admin__pb2.UsersResponse.FromString, + options, + channel_credentials, + insecure, + call_credentials, + compression, + wait_for_ready, + timeout, + metadata, + _registered_method=True) + + @staticmethod + def User(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary( + request, + target, + '/authorizer.v1.AuthorizerAdminService/User', + authorizer_dot_v1_dot_admin__pb2.UserRequest.SerializeToString, + authorizer_dot_v1_dot_admin__pb2.UserResponse.FromString, + options, + channel_credentials, + insecure, + call_credentials, + compression, + wait_for_ready, + timeout, + metadata, + _registered_method=True) + + @staticmethod + def UpdateUser(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary( + request, + target, + '/authorizer.v1.AuthorizerAdminService/UpdateUser', + authorizer_dot_v1_dot_admin__pb2.UpdateUserRequest.SerializeToString, + authorizer_dot_v1_dot_admin__pb2.UpdateUserResponse.FromString, + options, + channel_credentials, + insecure, + call_credentials, + compression, + wait_for_ready, + timeout, + metadata, + _registered_method=True) + + @staticmethod + def DeleteUser(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary( + request, + target, + '/authorizer.v1.AuthorizerAdminService/DeleteUser', + authorizer_dot_v1_dot_admin__pb2.DeleteUserRequest.SerializeToString, + authorizer_dot_v1_dot_admin__pb2.DeleteUserResponse.FromString, + options, + channel_credentials, + insecure, + call_credentials, + compression, + wait_for_ready, + timeout, + metadata, + _registered_method=True) + + @staticmethod + def VerificationRequests(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary( + request, + target, + '/authorizer.v1.AuthorizerAdminService/VerificationRequests', + authorizer_dot_v1_dot_admin__pb2.VerificationRequestsRequest.SerializeToString, + authorizer_dot_v1_dot_admin__pb2.VerificationRequestsResponse.FromString, + options, + channel_credentials, + insecure, + call_credentials, + compression, + wait_for_ready, + timeout, + metadata, + _registered_method=True) + + @staticmethod + def RevokeAccess(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary( + request, + target, + '/authorizer.v1.AuthorizerAdminService/RevokeAccess', + authorizer_dot_v1_dot_admin__pb2.RevokeAccessRequest.SerializeToString, + authorizer_dot_v1_dot_admin__pb2.RevokeAccessResponse.FromString, + options, + channel_credentials, + insecure, + call_credentials, + compression, + wait_for_ready, + timeout, + metadata, + _registered_method=True) + + @staticmethod + def EnableAccess(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary( + request, + target, + '/authorizer.v1.AuthorizerAdminService/EnableAccess', + authorizer_dot_v1_dot_admin__pb2.EnableAccessRequest.SerializeToString, + authorizer_dot_v1_dot_admin__pb2.EnableAccessResponse.FromString, + options, + channel_credentials, + insecure, + call_credentials, + compression, + wait_for_ready, + timeout, + metadata, + _registered_method=True) + + @staticmethod + def InviteMembers(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary( + request, + target, + '/authorizer.v1.AuthorizerAdminService/InviteMembers', + authorizer_dot_v1_dot_admin__pb2.InviteMembersRequest.SerializeToString, + authorizer_dot_v1_dot_admin__pb2.InviteMembersResponse.FromString, + options, + channel_credentials, + insecure, + call_credentials, + compression, + wait_for_ready, + timeout, + metadata, + _registered_method=True) + + @staticmethod + def AddWebhook(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary( + request, + target, + '/authorizer.v1.AuthorizerAdminService/AddWebhook', + authorizer_dot_v1_dot_admin__pb2.AddWebhookRequest.SerializeToString, + authorizer_dot_v1_dot_admin__pb2.AddWebhookResponse.FromString, + options, + channel_credentials, + insecure, + call_credentials, + compression, + wait_for_ready, + timeout, + metadata, + _registered_method=True) + + @staticmethod + def UpdateWebhook(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary( + request, + target, + '/authorizer.v1.AuthorizerAdminService/UpdateWebhook', + authorizer_dot_v1_dot_admin__pb2.UpdateWebhookRequest.SerializeToString, + authorizer_dot_v1_dot_admin__pb2.UpdateWebhookResponse.FromString, + options, + channel_credentials, + insecure, + call_credentials, + compression, + wait_for_ready, + timeout, + metadata, + _registered_method=True) + + @staticmethod + def DeleteWebhook(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary( + request, + target, + '/authorizer.v1.AuthorizerAdminService/DeleteWebhook', + authorizer_dot_v1_dot_admin__pb2.DeleteWebhookRequest.SerializeToString, + authorizer_dot_v1_dot_admin__pb2.DeleteWebhookResponse.FromString, + options, + channel_credentials, + insecure, + call_credentials, + compression, + wait_for_ready, + timeout, + metadata, + _registered_method=True) + + @staticmethod + def GetWebhook(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary( + request, + target, + '/authorizer.v1.AuthorizerAdminService/GetWebhook', + authorizer_dot_v1_dot_admin__pb2.GetWebhookRequest.SerializeToString, + authorizer_dot_v1_dot_admin__pb2.GetWebhookResponse.FromString, + options, + channel_credentials, + insecure, + call_credentials, + compression, + wait_for_ready, + timeout, + metadata, + _registered_method=True) + + @staticmethod + def Webhooks(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary( + request, + target, + '/authorizer.v1.AuthorizerAdminService/Webhooks', + authorizer_dot_v1_dot_admin__pb2.WebhooksRequest.SerializeToString, + authorizer_dot_v1_dot_admin__pb2.WebhooksResponse.FromString, + options, + channel_credentials, + insecure, + call_credentials, + compression, + wait_for_ready, + timeout, + metadata, + _registered_method=True) + + @staticmethod + def WebhookLogs(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary( + request, + target, + '/authorizer.v1.AuthorizerAdminService/WebhookLogs', + authorizer_dot_v1_dot_admin__pb2.WebhookLogsRequest.SerializeToString, + authorizer_dot_v1_dot_admin__pb2.WebhookLogsResponse.FromString, + options, + channel_credentials, + insecure, + call_credentials, + compression, + wait_for_ready, + timeout, + metadata, + _registered_method=True) + + @staticmethod + def TestEndpoint(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary( + request, + target, + '/authorizer.v1.AuthorizerAdminService/TestEndpoint', + authorizer_dot_v1_dot_admin__pb2.TestEndpointRequest.SerializeToString, + authorizer_dot_v1_dot_admin__pb2.TestEndpointResponse.FromString, + options, + channel_credentials, + insecure, + call_credentials, + compression, + wait_for_ready, + timeout, + metadata, + _registered_method=True) + + @staticmethod + def AddEmailTemplate(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary( + request, + target, + '/authorizer.v1.AuthorizerAdminService/AddEmailTemplate', + authorizer_dot_v1_dot_admin__pb2.AddEmailTemplateRequest.SerializeToString, + authorizer_dot_v1_dot_admin__pb2.AddEmailTemplateResponse.FromString, + options, + channel_credentials, + insecure, + call_credentials, + compression, + wait_for_ready, + timeout, + metadata, + _registered_method=True) + + @staticmethod + def UpdateEmailTemplate(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary( + request, + target, + '/authorizer.v1.AuthorizerAdminService/UpdateEmailTemplate', + authorizer_dot_v1_dot_admin__pb2.UpdateEmailTemplateRequest.SerializeToString, + authorizer_dot_v1_dot_admin__pb2.UpdateEmailTemplateResponse.FromString, + options, + channel_credentials, + insecure, + call_credentials, + compression, + wait_for_ready, + timeout, + metadata, + _registered_method=True) + + @staticmethod + def DeleteEmailTemplate(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary( + request, + target, + '/authorizer.v1.AuthorizerAdminService/DeleteEmailTemplate', + authorizer_dot_v1_dot_admin__pb2.DeleteEmailTemplateRequest.SerializeToString, + authorizer_dot_v1_dot_admin__pb2.DeleteEmailTemplateResponse.FromString, + options, + channel_credentials, + insecure, + call_credentials, + compression, + wait_for_ready, + timeout, + metadata, + _registered_method=True) + + @staticmethod + def EmailTemplates(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary( + request, + target, + '/authorizer.v1.AuthorizerAdminService/EmailTemplates', + authorizer_dot_v1_dot_admin__pb2.EmailTemplatesRequest.SerializeToString, + authorizer_dot_v1_dot_admin__pb2.EmailTemplatesResponse.FromString, + options, + channel_credentials, + insecure, + call_credentials, + compression, + wait_for_ready, + timeout, + metadata, + _registered_method=True) + + @staticmethod + def AuditLogs(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary( + request, + target, + '/authorizer.v1.AuthorizerAdminService/AuditLogs', + authorizer_dot_v1_dot_admin__pb2.AuditLogsRequest.SerializeToString, + authorizer_dot_v1_dot_admin__pb2.AuditLogsResponse.FromString, + options, + channel_credentials, + insecure, + call_credentials, + compression, + wait_for_ready, + timeout, + metadata, + _registered_method=True) + + @staticmethod + def FgaGetModel(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary( + request, + target, + '/authorizer.v1.AuthorizerAdminService/FgaGetModel', + authorizer_dot_v1_dot_admin__pb2.FgaGetModelRequest.SerializeToString, + authorizer_dot_v1_dot_admin__pb2.FgaGetModelResponse.FromString, + options, + channel_credentials, + insecure, + call_credentials, + compression, + wait_for_ready, + timeout, + metadata, + _registered_method=True) + + @staticmethod + def FgaWriteModel(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary( + request, + target, + '/authorizer.v1.AuthorizerAdminService/FgaWriteModel', + authorizer_dot_v1_dot_admin__pb2.FgaWriteModelRequest.SerializeToString, + authorizer_dot_v1_dot_admin__pb2.FgaWriteModelResponse.FromString, + options, + channel_credentials, + insecure, + call_credentials, + compression, + wait_for_ready, + timeout, + metadata, + _registered_method=True) + + @staticmethod + def FgaWriteTuples(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary( + request, + target, + '/authorizer.v1.AuthorizerAdminService/FgaWriteTuples', + authorizer_dot_v1_dot_admin__pb2.FgaWriteTuplesRequest.SerializeToString, + authorizer_dot_v1_dot_admin__pb2.FgaWriteTuplesResponse.FromString, + options, + channel_credentials, + insecure, + call_credentials, + compression, + wait_for_ready, + timeout, + metadata, + _registered_method=True) + + @staticmethod + def FgaDeleteTuples(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary( + request, + target, + '/authorizer.v1.AuthorizerAdminService/FgaDeleteTuples', + authorizer_dot_v1_dot_admin__pb2.FgaDeleteTuplesRequest.SerializeToString, + authorizer_dot_v1_dot_admin__pb2.FgaDeleteTuplesResponse.FromString, + options, + channel_credentials, + insecure, + call_credentials, + compression, + wait_for_ready, + timeout, + metadata, + _registered_method=True) + + @staticmethod + def FgaReadTuples(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary( + request, + target, + '/authorizer.v1.AuthorizerAdminService/FgaReadTuples', + authorizer_dot_v1_dot_admin__pb2.FgaReadTuplesRequest.SerializeToString, + authorizer_dot_v1_dot_admin__pb2.FgaReadTuplesResponse.FromString, + options, + channel_credentials, + insecure, + call_credentials, + compression, + wait_for_ready, + timeout, + metadata, + _registered_method=True) + + @staticmethod + def FgaListUsers(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary( + request, + target, + '/authorizer.v1.AuthorizerAdminService/FgaListUsers', + authorizer_dot_v1_dot_admin__pb2.FgaListUsersRequest.SerializeToString, + authorizer_dot_v1_dot_admin__pb2.FgaListUsersResponse.FromString, + options, + channel_credentials, + insecure, + call_credentials, + compression, + wait_for_ready, + timeout, + metadata, + _registered_method=True) + + @staticmethod + def FgaExpand(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary( + request, + target, + '/authorizer.v1.AuthorizerAdminService/FgaExpand', + authorizer_dot_v1_dot_admin__pb2.FgaExpandRequest.SerializeToString, + authorizer_dot_v1_dot_admin__pb2.FgaExpandResponse.FromString, + options, + channel_credentials, + insecure, + call_credentials, + compression, + wait_for_ready, + timeout, + metadata, + _registered_method=True) + + @staticmethod + def FgaReset(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary( + request, + target, + '/authorizer.v1.AuthorizerAdminService/FgaReset', + authorizer_dot_v1_dot_admin__pb2.FgaResetRequest.SerializeToString, + authorizer_dot_v1_dot_admin__pb2.FgaResetResponse.FromString, + options, + channel_credentials, + insecure, + call_credentials, + compression, + wait_for_ready, + timeout, + metadata, + _registered_method=True) diff --git a/src/authorizer/_grpc/authorizer/v1/annotations_pb2.py b/src/authorizer/_grpc/authorizer/v1/annotations_pb2.py new file mode 100644 index 0000000..30a1f15 --- /dev/null +++ b/src/authorizer/_grpc/authorizer/v1/annotations_pb2.py @@ -0,0 +1,40 @@ +# -*- coding: utf-8 -*- +# Generated by the protocol buffer compiler. DO NOT EDIT! +# NO CHECKED-IN PROTOBUF GENCODE +# source: authorizer/v1/annotations.proto +# Protobuf Python Version: 5.27.3 +"""Generated protocol buffer code.""" +from google.protobuf import descriptor as _descriptor +from google.protobuf import descriptor_pool as _descriptor_pool +from google.protobuf import runtime_version as _runtime_version +from google.protobuf import symbol_database as _symbol_database +from google.protobuf.internal import builder as _builder +_runtime_version.ValidateProtobufRuntimeVersion( + _runtime_version.Domain.PUBLIC, + 5, + 27, + 3, + '', + 'authorizer/v1/annotations.proto' +) +# @@protoc_insertion_point(imports) + +_sym_db = _symbol_database.Default() + + +from google.protobuf import descriptor_pb2 as google_dot_protobuf_dot_descriptor__pb2 + + +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x1f\x61uthorizer/v1/annotations.proto\x12\rauthorizer.v1\x1a google/protobuf/descriptor.proto\"I\n\x15PermissionRequirement\x12\x1a\n\x08resource\x18\x01 \x01(\tR\x08resource\x12\x14\n\x05scope\x18\x02 \x01(\tR\x05scope\"b\n\x07McpTool\x12\x18\n\x07\x65xposed\x18\x01 \x01(\x08R\x07\x65xposed\x12\x1b\n\ttool_name\x18\x02 \x01(\tR\x08toolName\x12 \n\x0b\x64\x65structive\x18\x03 \x01(\x08R\x0b\x64\x65structive:y\n\x14required_permissions\x12\x1e.google.protobuf.MethodOptions\x18\xd1\x86\x03 \x03(\x0b\x32$.authorizer.v1.PermissionRequirementR\x13requiredPermissions:S\n\x08mcp_tool\x12\x1e.google.protobuf.MethodOptions\x18\xd2\x86\x03 \x01(\x0b\x32\x16.authorizer.v1.McpToolR\x07mcpTool:=\n\taudit_log\x12\x1e.google.protobuf.MethodOptions\x18\xd3\x86\x03 \x01(\x08R\x08\x61uditLog:8\n\x06public\x12\x1e.google.protobuf.MethodOptions\x18\xd4\x86\x03 \x01(\x08R\x06publicB\xcc\x01\n\x11\x63om.authorizer.v1B\x10\x41nnotationsProtoP\x01ZPgithub.com/authorizerdev/authorizer-go/internal/genpb/authorizer/v1;authorizerv1\xa2\x02\x03\x41XX\xaa\x02\rAuthorizer.V1\xca\x02\rAuthorizer\\V1\xe2\x02\x19\x41uthorizer\\V1\\GPBMetadata\xea\x02\x0e\x41uthorizer::V1b\x06proto3') + +_globals = globals() +_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) +_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'authorizer.v1.annotations_pb2', _globals) +if not _descriptor._USE_C_DESCRIPTORS: + _globals['DESCRIPTOR']._loaded_options = None + _globals['DESCRIPTOR']._serialized_options = b'\n\021com.authorizer.v1B\020AnnotationsProtoP\001ZPgithub.com/authorizerdev/authorizer-go/internal/genpb/authorizer/v1;authorizerv1\242\002\003AXX\252\002\rAuthorizer.V1\312\002\rAuthorizer\\V1\342\002\031Authorizer\\V1\\GPBMetadata\352\002\016Authorizer::V1' + _globals['_PERMISSIONREQUIREMENT']._serialized_start=84 + _globals['_PERMISSIONREQUIREMENT']._serialized_end=157 + _globals['_MCPTOOL']._serialized_start=159 + _globals['_MCPTOOL']._serialized_end=257 +# @@protoc_insertion_point(module_scope) diff --git a/src/authorizer/_grpc/authorizer/v1/annotations_pb2_grpc.py b/src/authorizer/_grpc/authorizer/v1/annotations_pb2_grpc.py new file mode 100644 index 0000000..2daafff --- /dev/null +++ b/src/authorizer/_grpc/authorizer/v1/annotations_pb2_grpc.py @@ -0,0 +1,4 @@ +# Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT! +"""Client and server classes corresponding to protobuf-defined services.""" +import grpc + diff --git a/src/authorizer/_grpc/authorizer/v1/authorizer_pb2.py b/src/authorizer/_grpc/authorizer/v1/authorizer_pb2.py new file mode 100644 index 0000000..f5f1faa --- /dev/null +++ b/src/authorizer/_grpc/authorizer/v1/authorizer_pb2.py @@ -0,0 +1,208 @@ +# -*- coding: utf-8 -*- +# Generated by the protocol buffer compiler. DO NOT EDIT! +# NO CHECKED-IN PROTOBUF GENCODE +# source: authorizer/v1/authorizer.proto +# Protobuf Python Version: 5.27.3 +"""Generated protocol buffer code.""" +from google.protobuf import descriptor as _descriptor +from google.protobuf import descriptor_pool as _descriptor_pool +from google.protobuf import runtime_version as _runtime_version +from google.protobuf import symbol_database as _symbol_database +from google.protobuf.internal import builder as _builder +_runtime_version.ValidateProtobufRuntimeVersion( + _runtime_version.Domain.PUBLIC, + 5, + 27, + 3, + '', + 'authorizer/v1/authorizer.proto' +) +# @@protoc_insertion_point(imports) + +_sym_db = _symbol_database.Default() + + +from authorizer._grpc.authorizer.v1 import annotations_pb2 as authorizer_dot_v1_dot_annotations__pb2 +from authorizer._grpc.authorizer.v1 import common_pb2 as authorizer_dot_v1_dot_common__pb2 +from authorizer._grpc.authorizer.v1 import types_pb2 as authorizer_dot_v1_dot_types__pb2 +from authorizer._grpc.buf.validate import validate_pb2 as buf_dot_validate_dot_validate__pb2 +from authorizer._grpc.google.api import annotations_pb2 as google_dot_api_dot_annotations__pb2 + + +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x1e\x61uthorizer/v1/authorizer.proto\x12\rauthorizer.v1\x1a\x1f\x61uthorizer/v1/annotations.proto\x1a\x1a\x61uthorizer/v1/common.proto\x1a\x19\x61uthorizer/v1/types.proto\x1a\x1b\x62uf/validate/validate.proto\x1a\x1cgoogle/api/annotations.proto\"\xdf\x04\n\rSignupRequest\x12\x1e\n\x05\x65mail\x18\x01 \x01(\tB\x08\xbaH\x05r\x03\x18\xc0\x02R\x05\x65mail\x12*\n\x0cphone_number\x18\x02 \x01(\tB\x07\xbaH\x04r\x02\x18 R\x0bphoneNumber\x12&\n\x08password\x18\x03 \x01(\tB\n\xbaH\x07r\x05\x10\x01\x18\x80\x01R\x08password\x12\x35\n\x10\x63onfirm_password\x18\x04 \x01(\tB\n\xbaH\x07r\x05\x10\x01\x18\x80\x01R\x0f\x63onfirmPassword\x12\x1d\n\ngiven_name\x18\x05 \x01(\tR\tgivenName\x12\x1f\n\x0b\x66\x61mily_name\x18\x06 \x01(\tR\nfamilyName\x12\x1f\n\x0bmiddle_name\x18\x07 \x01(\tR\nmiddleName\x12\x1a\n\x08nickname\x18\x08 \x01(\tR\x08nickname\x12\x16\n\x06gender\x18\t \x01(\tR\x06gender\x12\x1c\n\tbirthdate\x18\n \x01(\tR\tbirthdate\x12\x18\n\x07picture\x18\x0b \x01(\tR\x07picture\x12\x14\n\x05roles\x18\x0c \x03(\tR\x05roles\x12\x14\n\x05scope\x18\r \x03(\tR\x05scope\x12!\n\x0credirect_uri\x18\x0e \x01(\tR\x0bredirectUri\x12>\n\x1cis_multi_factor_auth_enabled\x18\x0f \x01(\x08R\x18isMultiFactorAuthEnabled\x12\x14\n\x05state\x18\x10 \x01(\tR\x05state\x12\x31\n\x08\x61pp_data\x18\x11 \x01(\x0b\x32\x16.authorizer.v1.AppDataR\x07\x61ppData\"\xc4\x01\n\x0cLoginRequest\x12\x1e\n\x05\x65mail\x18\x01 \x01(\tB\x08\xbaH\x05r\x03\x18\xc0\x02R\x05\x65mail\x12*\n\x0cphone_number\x18\x02 \x01(\tB\x07\xbaH\x04r\x02\x18 R\x0bphoneNumber\x12&\n\x08password\x18\x03 \x01(\tB\n\xbaH\x07r\x05\x10\x01\x18\x80\x01R\x08password\x12\x14\n\x05roles\x18\x04 \x03(\tR\x05roles\x12\x14\n\x05scope\x18\x05 \x03(\tR\x05scope\x12\x14\n\x05state\x18\x06 \x01(\tR\x05state\"\x0f\n\rLogoutRequest\"*\n\x0eLogoutResponse\x12\x18\n\x07message\x18\x01 \x01(\tR\x07message\"\x9c\x01\n\x15MagicLinkLoginRequest\x12\x1e\n\x05\x65mail\x18\x01 \x01(\tB\x08\xbaH\x05r\x03\x18\xc0\x02R\x05\x65mail\x12\x14\n\x05roles\x18\x02 \x03(\tR\x05roles\x12\x14\n\x05scope\x18\x03 \x03(\tR\x05scope\x12\x14\n\x05state\x18\x04 \x01(\tR\x05state\x12!\n\x0credirect_uri\x18\x05 \x01(\tR\x0bredirectUri\"2\n\x16MagicLinkLoginResponse\x12\x18\n\x07message\x18\x01 \x01(\tR\x07message\"I\n\x12VerifyEmailRequest\x12\x1d\n\x05token\x18\x01 \x01(\tB\x07\xbaH\x04r\x02\x10\x01R\x05token\x12\x14\n\x05state\x18\x02 \x01(\tR\x05state\"y\n\x18ResendVerifyEmailRequest\x12\x1e\n\x05\x65mail\x18\x01 \x01(\tB\x08\xbaH\x05r\x03\x18\xc0\x02R\x05\x65mail\x12\'\n\nidentifier\x18\x02 \x01(\tB\x07\xbaH\x04r\x02\x10\x01R\nidentifier\x12\x14\n\x05state\x18\x03 \x01(\tR\x05state\"5\n\x19ResendVerifyEmailResponse\x12\x18\n\x07message\x18\x01 \x01(\tR\x07message\"\xaa\x01\n\x10VerifyOtpRequest\x12\x1e\n\x05\x65mail\x18\x01 \x01(\tB\x08\xbaH\x05r\x03\x18\xc0\x02R\x05\x65mail\x12*\n\x0cphone_number\x18\x02 \x01(\tB\x07\xbaH\x04r\x02\x18 R\x0bphoneNumber\x12\x1b\n\x03otp\x18\x03 \x01(\tB\t\xbaH\x06r\x04\x10\x01\x18\x10R\x03otp\x12\x17\n\x07is_totp\x18\x04 \x01(\x08R\x06isTotp\x12\x14\n\x05state\x18\x05 \x01(\tR\x05state\"t\n\x10ResendOtpRequest\x12\x1e\n\x05\x65mail\x18\x01 \x01(\tB\x08\xbaH\x05r\x03\x18\xc0\x02R\x05\x65mail\x12*\n\x0cphone_number\x18\x02 \x01(\tB\x07\xbaH\x04r\x02\x18 R\x0bphoneNumber\x12\x14\n\x05state\x18\x03 \x01(\tR\x05state\"-\n\x11ResendOtpResponse\x12\x18\n\x07message\x18\x01 \x01(\tR\x07message\"\x9c\x01\n\x15\x46orgotPasswordRequest\x12\x1e\n\x05\x65mail\x18\x01 \x01(\tB\x08\xbaH\x05r\x03\x18\xc0\x02R\x05\x65mail\x12*\n\x0cphone_number\x18\x02 \x01(\tB\x07\xbaH\x04r\x02\x18 R\x0bphoneNumber\x12\x14\n\x05state\x18\x03 \x01(\tR\x05state\x12!\n\x0credirect_uri\x18\x04 \x01(\tR\x0bredirectUri\"t\n\x16\x46orgotPasswordResponse\x12\x18\n\x07message\x18\x01 \x01(\tR\x07message\x12@\n\x1dshould_show_mobile_otp_screen\x18\x02 \x01(\x08R\x19shouldShowMobileOtpScreen\"\xc9\x01\n\x14ResetPasswordRequest\x12\x14\n\x05token\x18\x01 \x01(\tR\x05token\x12\x10\n\x03otp\x18\x02 \x01(\tR\x03otp\x12*\n\x0cphone_number\x18\x03 \x01(\tB\x07\xbaH\x04r\x02\x18 R\x0bphoneNumber\x12&\n\x08password\x18\x04 \x01(\tB\n\xbaH\x07r\x05\x10\x01\x18\x80\x01R\x08password\x12\x35\n\x10\x63onfirm_password\x18\x05 \x01(\tB\n\xbaH\x07r\x05\x10\x01\x18\x80\x01R\x0f\x63onfirmPassword\"1\n\x15ResetPasswordResponse\x12\x18\n\x07message\x18\x01 \x01(\tR\x07message\"\x10\n\x0eProfileRequest\"\xd4\x04\n\x14UpdateProfileRequest\x12!\n\x0cold_password\x18\x01 \x01(\tR\x0boldPassword\x12+\n\x0cnew_password\x18\x02 \x01(\tB\x08\xbaH\x05r\x03\x18\x80\x01R\x0bnewPassword\x12:\n\x14\x63onfirm_new_password\x18\x03 \x01(\tB\x08\xbaH\x05r\x03\x18\x80\x01R\x12\x63onfirmNewPassword\x12\x1e\n\x05\x65mail\x18\x04 \x01(\tB\x08\xbaH\x05r\x03\x18\xc0\x02R\x05\x65mail\x12\x1d\n\ngiven_name\x18\x05 \x01(\tR\tgivenName\x12\x1f\n\x0b\x66\x61mily_name\x18\x06 \x01(\tR\nfamilyName\x12\x1f\n\x0bmiddle_name\x18\x07 \x01(\tR\nmiddleName\x12\x1a\n\x08nickname\x18\x08 \x01(\tR\x08nickname\x12\x16\n\x06gender\x18\t \x01(\tR\x06gender\x12\x1c\n\tbirthdate\x18\n \x01(\tR\tbirthdate\x12*\n\x0cphone_number\x18\x0b \x01(\tB\x07\xbaH\x04r\x02\x18 R\x0bphoneNumber\x12\x18\n\x07picture\x18\x0c \x01(\tR\x07picture\x12\x43\n\x1cis_multi_factor_auth_enabled\x18\r \x01(\x08H\x00R\x18isMultiFactorAuthEnabled\x88\x01\x01\x12\x31\n\x08\x61pp_data\x18\x0e \x01(\x0b\x32\x16.authorizer.v1.AppDataR\x07\x61ppDataB\x1f\n\x1d_is_multi_factor_auth_enabled\"1\n\x15UpdateProfileResponse\x12\x18\n\x07message\x18\x01 \x01(\tR\x07message\"\x1a\n\x18\x44\x65\x61\x63tivateAccountRequest\"5\n\x19\x44\x65\x61\x63tivateAccountResponse\x12\x18\n\x07message\x18\x01 \x01(\tR\x07message\"=\n\rRevokeRequest\x12,\n\rrefresh_token\x18\x01 \x01(\tB\x07\xbaH\x04r\x02\x10\x01R\x0crefreshToken\"*\n\x0eRevokeResponse\x12\x18\n\x07message\x18\x01 \x01(\tR\x07message\"\xa2\x01\n\x0eSessionRequest\x12\x14\n\x05roles\x18\x01 \x03(\tR\x05roles\x12\x14\n\x05scope\x18\x02 \x03(\tR\x05scope\x12\x14\n\x05state\x18\x03 \x01(\tR\x05state\x12N\n\x12required_relations\x18\x04 \x03(\x0b\x32\x1f.authorizer.v1.FgaRelationInputR\x11requiredRelations\"\xc6\x01\n\x17ValidateJwtTokenRequest\x12&\n\ntoken_type\x18\x01 \x01(\tB\x07\xbaH\x04r\x02\x10\x01R\ttokenType\x12\x1d\n\x05token\x18\x02 \x01(\tB\x07\xbaH\x04r\x02\x10\x01R\x05token\x12\x14\n\x05roles\x18\x03 \x03(\tR\x05roles\x12N\n\x12required_relations\x18\x04 \x03(\x0b\x32\x1f.authorizer.v1.FgaRelationInputR\x11requiredRelations\"e\n\x18ValidateJwtTokenResponse\x12\x19\n\x08is_valid\x18\x01 \x01(\x08R\x07isValid\x12.\n\x06\x63laims\x18\x02 \x01(\x0b\x32\x16.authorizer.v1.AppDataR\x06\x63laims\"\x9f\x01\n\x16ValidateSessionRequest\x12\x1f\n\x06\x63ookie\x18\x01 \x01(\tB\x07\xbaH\x04r\x02\x10\x01R\x06\x63ookie\x12\x14\n\x05roles\x18\x02 \x03(\tR\x05roles\x12N\n\x12required_relations\x18\x03 \x03(\x0b\x32\x1f.authorizer.v1.FgaRelationInputR\x11requiredRelations\"]\n\x17ValidateSessionResponse\x12\x19\n\x08is_valid\x18\x01 \x01(\x08R\x07isValid\x12\'\n\x04user\x18\x02 \x01(\x0b\x32\x13.authorizer.v1.UserR\x04user\"\r\n\x0bMetaRequest\"v\n\x17\x43heckPermissionsRequest\x12G\n\x06\x63hecks\x18\x01 \x03(\x0b\x32#.authorizer.v1.PermissionCheckInputB\n\xbaH\x07\x92\x01\x04\x08\x01\x10\x64R\x06\x63hecks\x12\x12\n\x04user\x18\x02 \x01(\tR\x04user\"Z\n\x18\x43heckPermissionsResponse\x12>\n\x07results\x18\x01 \x03(\x0b\x32$.authorizer.v1.PermissionCheckResultR\x07results\"i\n\x16ListPermissionsRequest\x12\x1a\n\x08relation\x18\x01 \x01(\tR\x08relation\x12\x1f\n\x0bobject_type\x18\x02 \x01(\tR\nobjectType\x12\x12\n\x04user\x18\x03 \x01(\tR\x04user\"\x8e\x01\n\x17ListPermissionsResponse\x12\x18\n\x07objects\x18\x01 \x03(\tR\x07objects\x12;\n\x0bpermissions\x18\x02 \x03(\x0b\x32\x19.authorizer.v1.PermissionR\x0bpermissions\x12\x1c\n\ttruncated\x18\x03 \x01(\x08R\ttruncated2\xe8\x12\n\x11\x41uthorizerService\x12\x66\n\x06Signup\x12\x1c.authorizer.v1.SignupRequest\x1a\x1b.authorizer.v1.AuthResponse\"!\x92\xb5\x18\x00\x98\xb5\x18\x01\xa0\xb5\x18\x01\x82\xd3\xe4\x93\x02\x0f\"\n/v1/signup:\x01*\x12\x63\n\x05Login\x12\x1b.authorizer.v1.LoginRequest\x1a\x1b.authorizer.v1.AuthResponse\" \x92\xb5\x18\x00\x98\xb5\x18\x01\xa0\xb5\x18\x01\x82\xd3\xe4\x93\x02\x0e\"\t/v1/login:\x01*\x12]\n\x06Logout\x12\x1c.authorizer.v1.LogoutRequest\x1a\x1d.authorizer.v1.LogoutResponse\"\x16\x98\xb5\x18\x01\x82\xd3\xe4\x93\x02\x0c\"\n/v1/logout\x12\x86\x01\n\x0eMagicLinkLogin\x12$.authorizer.v1.MagicLinkLoginRequest\x1a%.authorizer.v1.MagicLinkLoginResponse\"\'\x98\xb5\x18\x01\xa0\xb5\x18\x01\x82\xd3\xe4\x93\x02\x19\"\x14/v1/magic_link_login:\x01*\x12r\n\x0bVerifyEmail\x12!.authorizer.v1.VerifyEmailRequest\x1a\x1b.authorizer.v1.AuthResponse\"#\x98\xb5\x18\x01\xa0\xb5\x18\x01\x82\xd3\xe4\x93\x02\x15\"\x10/v1/verify_email:\x01*\x12\x8e\x01\n\x11ResendVerifyEmail\x12\'.authorizer.v1.ResendVerifyEmailRequest\x1a(.authorizer.v1.ResendVerifyEmailResponse\"&\xa0\xb5\x18\x01\x82\xd3\xe4\x93\x02\x1c\"\x17/v1/resend_verify_email:\x01*\x12l\n\tVerifyOtp\x12\x1f.authorizer.v1.VerifyOtpRequest\x1a\x1b.authorizer.v1.AuthResponse\"!\x98\xb5\x18\x01\xa0\xb5\x18\x01\x82\xd3\xe4\x93\x02\x13\"\x0e/v1/verify_otp:\x01*\x12m\n\tResendOtp\x12\x1f.authorizer.v1.ResendOtpRequest\x1a .authorizer.v1.ResendOtpResponse\"\x1d\xa0\xb5\x18\x01\x82\xd3\xe4\x93\x02\x13\"\x0e/v1/resend_otp:\x01*\x12\x81\x01\n\x0e\x46orgotPassword\x12$.authorizer.v1.ForgotPasswordRequest\x1a%.authorizer.v1.ForgotPasswordResponse\"\"\xa0\xb5\x18\x01\x82\xd3\xe4\x93\x02\x18\"\x13/v1/forgot_password:\x01*\x12\x81\x01\n\rResetPassword\x12#.authorizer.v1.ResetPasswordRequest\x1a$.authorizer.v1.ResetPasswordResponse\"%\x98\xb5\x18\x01\xa0\xb5\x18\x01\x82\xd3\xe4\x93\x02\x17\"\x12/v1/reset_password:\x01*\x12X\n\x07Profile\x12\x1d.authorizer.v1.ProfileRequest\x1a\x13.authorizer.v1.User\"\x19\x92\xb5\x18\x02\x08\x01\x82\xd3\xe4\x93\x02\r\x12\x0b/v1/profile\x12}\n\rUpdateProfile\x12#.authorizer.v1.UpdateProfileRequest\x1a$.authorizer.v1.UpdateProfileResponse\"!\x98\xb5\x18\x01\x82\xd3\xe4\x93\x02\x17\"\x12/v1/update_profile:\x01*\x12\x93\x01\n\x11\x44\x65\x61\x63tivateAccount\x12\'.authorizer.v1.DeactivateAccountRequest\x1a(.authorizer.v1.DeactivateAccountResponse\"+\x92\xb5\x18\x02\x18\x01\x98\xb5\x18\x01\x82\xd3\xe4\x93\x02\x1b\"\x16/v1/deactivate_account:\x01*\x12\x64\n\x06Revoke\x12\x1c.authorizer.v1.RevokeRequest\x1a\x1d.authorizer.v1.RevokeResponse\"\x1d\x98\xb5\x18\x01\xa0\xb5\x18\x01\x82\xd3\xe4\x93\x02\x0f\"\n/v1/revoke:\x01*\x12]\n\x07Session\x12\x1d.authorizer.v1.SessionRequest\x1a\x1b.authorizer.v1.AuthResponse\"\x16\x82\xd3\xe4\x93\x02\x10\"\x0b/v1/session:\x01*\x12\x8a\x01\n\x10ValidateJwtToken\x12&.authorizer.v1.ValidateJwtTokenRequest\x1a\'.authorizer.v1.ValidateJwtTokenResponse\"%\xa0\xb5\x18\x01\x82\xd3\xe4\x93\x02\x1b\"\x16/v1/validate_jwt_token:\x01*\x12\x85\x01\n\x0fValidateSession\x12%.authorizer.v1.ValidateSessionRequest\x1a&.authorizer.v1.ValidateSessionResponse\"#\xa0\xb5\x18\x01\x82\xd3\xe4\x93\x02\x19\"\x14/v1/validate_session:\x01*\x12S\n\x04Meta\x12\x1a.authorizer.v1.MetaRequest\x1a\x13.authorizer.v1.Meta\"\x1a\x92\xb5\x18\x02\x08\x01\xa0\xb5\x18\x01\x82\xd3\xe4\x93\x02\n\x12\x08/v1/meta\x12\x8b\x01\n\x10\x43heckPermissions\x12&.authorizer.v1.CheckPermissionsRequest\x1a\'.authorizer.v1.CheckPermissionsResponse\"&\x92\xb5\x18\x02\x08\x01\x82\xd3\xe4\x93\x02\x1a\"\x15/v1/check_permissions:\x01*\x12\x87\x01\n\x0fListPermissions\x12%.authorizer.v1.ListPermissionsRequest\x1a&.authorizer.v1.ListPermissionsResponse\"%\x92\xb5\x18\x02\x08\x01\x82\xd3\xe4\x93\x02\x19\"\x14/v1/list_permissions:\x01*B\xcb\x01\n\x11\x63om.authorizer.v1B\x0f\x41uthorizerProtoP\x01ZPgithub.com/authorizerdev/authorizer-go/internal/genpb/authorizer/v1;authorizerv1\xa2\x02\x03\x41XX\xaa\x02\rAuthorizer.V1\xca\x02\rAuthorizer\\V1\xe2\x02\x19\x41uthorizer\\V1\\GPBMetadata\xea\x02\x0e\x41uthorizer::V1b\x06proto3') + +_globals = globals() +_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) +_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'authorizer.v1.authorizer_pb2', _globals) +if not _descriptor._USE_C_DESCRIPTORS: + _globals['DESCRIPTOR']._loaded_options = None + _globals['DESCRIPTOR']._serialized_options = b'\n\021com.authorizer.v1B\017AuthorizerProtoP\001ZPgithub.com/authorizerdev/authorizer-go/internal/genpb/authorizer/v1;authorizerv1\242\002\003AXX\252\002\rAuthorizer.V1\312\002\rAuthorizer\\V1\342\002\031Authorizer\\V1\\GPBMetadata\352\002\016Authorizer::V1' + _globals['_SIGNUPREQUEST'].fields_by_name['email']._loaded_options = None + _globals['_SIGNUPREQUEST'].fields_by_name['email']._serialized_options = b'\272H\005r\003\030\300\002' + _globals['_SIGNUPREQUEST'].fields_by_name['phone_number']._loaded_options = None + _globals['_SIGNUPREQUEST'].fields_by_name['phone_number']._serialized_options = b'\272H\004r\002\030 ' + _globals['_SIGNUPREQUEST'].fields_by_name['password']._loaded_options = None + _globals['_SIGNUPREQUEST'].fields_by_name['password']._serialized_options = b'\272H\007r\005\020\001\030\200\001' + _globals['_SIGNUPREQUEST'].fields_by_name['confirm_password']._loaded_options = None + _globals['_SIGNUPREQUEST'].fields_by_name['confirm_password']._serialized_options = b'\272H\007r\005\020\001\030\200\001' + _globals['_LOGINREQUEST'].fields_by_name['email']._loaded_options = None + _globals['_LOGINREQUEST'].fields_by_name['email']._serialized_options = b'\272H\005r\003\030\300\002' + _globals['_LOGINREQUEST'].fields_by_name['phone_number']._loaded_options = None + _globals['_LOGINREQUEST'].fields_by_name['phone_number']._serialized_options = b'\272H\004r\002\030 ' + _globals['_LOGINREQUEST'].fields_by_name['password']._loaded_options = None + _globals['_LOGINREQUEST'].fields_by_name['password']._serialized_options = b'\272H\007r\005\020\001\030\200\001' + _globals['_MAGICLINKLOGINREQUEST'].fields_by_name['email']._loaded_options = None + _globals['_MAGICLINKLOGINREQUEST'].fields_by_name['email']._serialized_options = b'\272H\005r\003\030\300\002' + _globals['_VERIFYEMAILREQUEST'].fields_by_name['token']._loaded_options = None + _globals['_VERIFYEMAILREQUEST'].fields_by_name['token']._serialized_options = b'\272H\004r\002\020\001' + _globals['_RESENDVERIFYEMAILREQUEST'].fields_by_name['email']._loaded_options = None + _globals['_RESENDVERIFYEMAILREQUEST'].fields_by_name['email']._serialized_options = b'\272H\005r\003\030\300\002' + _globals['_RESENDVERIFYEMAILREQUEST'].fields_by_name['identifier']._loaded_options = None + _globals['_RESENDVERIFYEMAILREQUEST'].fields_by_name['identifier']._serialized_options = b'\272H\004r\002\020\001' + _globals['_VERIFYOTPREQUEST'].fields_by_name['email']._loaded_options = None + _globals['_VERIFYOTPREQUEST'].fields_by_name['email']._serialized_options = b'\272H\005r\003\030\300\002' + _globals['_VERIFYOTPREQUEST'].fields_by_name['phone_number']._loaded_options = None + _globals['_VERIFYOTPREQUEST'].fields_by_name['phone_number']._serialized_options = b'\272H\004r\002\030 ' + _globals['_VERIFYOTPREQUEST'].fields_by_name['otp']._loaded_options = None + _globals['_VERIFYOTPREQUEST'].fields_by_name['otp']._serialized_options = b'\272H\006r\004\020\001\030\020' + _globals['_RESENDOTPREQUEST'].fields_by_name['email']._loaded_options = None + _globals['_RESENDOTPREQUEST'].fields_by_name['email']._serialized_options = b'\272H\005r\003\030\300\002' + _globals['_RESENDOTPREQUEST'].fields_by_name['phone_number']._loaded_options = None + _globals['_RESENDOTPREQUEST'].fields_by_name['phone_number']._serialized_options = b'\272H\004r\002\030 ' + _globals['_FORGOTPASSWORDREQUEST'].fields_by_name['email']._loaded_options = None + _globals['_FORGOTPASSWORDREQUEST'].fields_by_name['email']._serialized_options = b'\272H\005r\003\030\300\002' + _globals['_FORGOTPASSWORDREQUEST'].fields_by_name['phone_number']._loaded_options = None + _globals['_FORGOTPASSWORDREQUEST'].fields_by_name['phone_number']._serialized_options = b'\272H\004r\002\030 ' + _globals['_RESETPASSWORDREQUEST'].fields_by_name['phone_number']._loaded_options = None + _globals['_RESETPASSWORDREQUEST'].fields_by_name['phone_number']._serialized_options = b'\272H\004r\002\030 ' + _globals['_RESETPASSWORDREQUEST'].fields_by_name['password']._loaded_options = None + _globals['_RESETPASSWORDREQUEST'].fields_by_name['password']._serialized_options = b'\272H\007r\005\020\001\030\200\001' + _globals['_RESETPASSWORDREQUEST'].fields_by_name['confirm_password']._loaded_options = None + _globals['_RESETPASSWORDREQUEST'].fields_by_name['confirm_password']._serialized_options = b'\272H\007r\005\020\001\030\200\001' + _globals['_UPDATEPROFILEREQUEST'].fields_by_name['new_password']._loaded_options = None + _globals['_UPDATEPROFILEREQUEST'].fields_by_name['new_password']._serialized_options = b'\272H\005r\003\030\200\001' + _globals['_UPDATEPROFILEREQUEST'].fields_by_name['confirm_new_password']._loaded_options = None + _globals['_UPDATEPROFILEREQUEST'].fields_by_name['confirm_new_password']._serialized_options = b'\272H\005r\003\030\200\001' + _globals['_UPDATEPROFILEREQUEST'].fields_by_name['email']._loaded_options = None + _globals['_UPDATEPROFILEREQUEST'].fields_by_name['email']._serialized_options = b'\272H\005r\003\030\300\002' + _globals['_UPDATEPROFILEREQUEST'].fields_by_name['phone_number']._loaded_options = None + _globals['_UPDATEPROFILEREQUEST'].fields_by_name['phone_number']._serialized_options = b'\272H\004r\002\030 ' + _globals['_REVOKEREQUEST'].fields_by_name['refresh_token']._loaded_options = None + _globals['_REVOKEREQUEST'].fields_by_name['refresh_token']._serialized_options = b'\272H\004r\002\020\001' + _globals['_VALIDATEJWTTOKENREQUEST'].fields_by_name['token_type']._loaded_options = None + _globals['_VALIDATEJWTTOKENREQUEST'].fields_by_name['token_type']._serialized_options = b'\272H\004r\002\020\001' + _globals['_VALIDATEJWTTOKENREQUEST'].fields_by_name['token']._loaded_options = None + _globals['_VALIDATEJWTTOKENREQUEST'].fields_by_name['token']._serialized_options = b'\272H\004r\002\020\001' + _globals['_VALIDATESESSIONREQUEST'].fields_by_name['cookie']._loaded_options = None + _globals['_VALIDATESESSIONREQUEST'].fields_by_name['cookie']._serialized_options = b'\272H\004r\002\020\001' + _globals['_CHECKPERMISSIONSREQUEST'].fields_by_name['checks']._loaded_options = None + _globals['_CHECKPERMISSIONSREQUEST'].fields_by_name['checks']._serialized_options = b'\272H\007\222\001\004\010\001\020d' + _globals['_AUTHORIZERSERVICE'].methods_by_name['Signup']._loaded_options = None + _globals['_AUTHORIZERSERVICE'].methods_by_name['Signup']._serialized_options = b'\222\265\030\000\230\265\030\001\240\265\030\001\202\323\344\223\002\017\"\n/v1/signup:\001*' + _globals['_AUTHORIZERSERVICE'].methods_by_name['Login']._loaded_options = None + _globals['_AUTHORIZERSERVICE'].methods_by_name['Login']._serialized_options = b'\222\265\030\000\230\265\030\001\240\265\030\001\202\323\344\223\002\016\"\t/v1/login:\001*' + _globals['_AUTHORIZERSERVICE'].methods_by_name['Logout']._loaded_options = None + _globals['_AUTHORIZERSERVICE'].methods_by_name['Logout']._serialized_options = b'\230\265\030\001\202\323\344\223\002\014\"\n/v1/logout' + _globals['_AUTHORIZERSERVICE'].methods_by_name['MagicLinkLogin']._loaded_options = None + _globals['_AUTHORIZERSERVICE'].methods_by_name['MagicLinkLogin']._serialized_options = b'\230\265\030\001\240\265\030\001\202\323\344\223\002\031\"\024/v1/magic_link_login:\001*' + _globals['_AUTHORIZERSERVICE'].methods_by_name['VerifyEmail']._loaded_options = None + _globals['_AUTHORIZERSERVICE'].methods_by_name['VerifyEmail']._serialized_options = b'\230\265\030\001\240\265\030\001\202\323\344\223\002\025\"\020/v1/verify_email:\001*' + _globals['_AUTHORIZERSERVICE'].methods_by_name['ResendVerifyEmail']._loaded_options = None + _globals['_AUTHORIZERSERVICE'].methods_by_name['ResendVerifyEmail']._serialized_options = b'\240\265\030\001\202\323\344\223\002\034\"\027/v1/resend_verify_email:\001*' + _globals['_AUTHORIZERSERVICE'].methods_by_name['VerifyOtp']._loaded_options = None + _globals['_AUTHORIZERSERVICE'].methods_by_name['VerifyOtp']._serialized_options = b'\230\265\030\001\240\265\030\001\202\323\344\223\002\023\"\016/v1/verify_otp:\001*' + _globals['_AUTHORIZERSERVICE'].methods_by_name['ResendOtp']._loaded_options = None + _globals['_AUTHORIZERSERVICE'].methods_by_name['ResendOtp']._serialized_options = b'\240\265\030\001\202\323\344\223\002\023\"\016/v1/resend_otp:\001*' + _globals['_AUTHORIZERSERVICE'].methods_by_name['ForgotPassword']._loaded_options = None + _globals['_AUTHORIZERSERVICE'].methods_by_name['ForgotPassword']._serialized_options = b'\240\265\030\001\202\323\344\223\002\030\"\023/v1/forgot_password:\001*' + _globals['_AUTHORIZERSERVICE'].methods_by_name['ResetPassword']._loaded_options = None + _globals['_AUTHORIZERSERVICE'].methods_by_name['ResetPassword']._serialized_options = b'\230\265\030\001\240\265\030\001\202\323\344\223\002\027\"\022/v1/reset_password:\001*' + _globals['_AUTHORIZERSERVICE'].methods_by_name['Profile']._loaded_options = None + _globals['_AUTHORIZERSERVICE'].methods_by_name['Profile']._serialized_options = b'\222\265\030\002\010\001\202\323\344\223\002\r\022\013/v1/profile' + _globals['_AUTHORIZERSERVICE'].methods_by_name['UpdateProfile']._loaded_options = None + _globals['_AUTHORIZERSERVICE'].methods_by_name['UpdateProfile']._serialized_options = b'\230\265\030\001\202\323\344\223\002\027\"\022/v1/update_profile:\001*' + _globals['_AUTHORIZERSERVICE'].methods_by_name['DeactivateAccount']._loaded_options = None + _globals['_AUTHORIZERSERVICE'].methods_by_name['DeactivateAccount']._serialized_options = b'\222\265\030\002\030\001\230\265\030\001\202\323\344\223\002\033\"\026/v1/deactivate_account:\001*' + _globals['_AUTHORIZERSERVICE'].methods_by_name['Revoke']._loaded_options = None + _globals['_AUTHORIZERSERVICE'].methods_by_name['Revoke']._serialized_options = b'\230\265\030\001\240\265\030\001\202\323\344\223\002\017\"\n/v1/revoke:\001*' + _globals['_AUTHORIZERSERVICE'].methods_by_name['Session']._loaded_options = None + _globals['_AUTHORIZERSERVICE'].methods_by_name['Session']._serialized_options = b'\202\323\344\223\002\020\"\013/v1/session:\001*' + _globals['_AUTHORIZERSERVICE'].methods_by_name['ValidateJwtToken']._loaded_options = None + _globals['_AUTHORIZERSERVICE'].methods_by_name['ValidateJwtToken']._serialized_options = b'\240\265\030\001\202\323\344\223\002\033\"\026/v1/validate_jwt_token:\001*' + _globals['_AUTHORIZERSERVICE'].methods_by_name['ValidateSession']._loaded_options = None + _globals['_AUTHORIZERSERVICE'].methods_by_name['ValidateSession']._serialized_options = b'\240\265\030\001\202\323\344\223\002\031\"\024/v1/validate_session:\001*' + _globals['_AUTHORIZERSERVICE'].methods_by_name['Meta']._loaded_options = None + _globals['_AUTHORIZERSERVICE'].methods_by_name['Meta']._serialized_options = b'\222\265\030\002\010\001\240\265\030\001\202\323\344\223\002\n\022\010/v1/meta' + _globals['_AUTHORIZERSERVICE'].methods_by_name['CheckPermissions']._loaded_options = None + _globals['_AUTHORIZERSERVICE'].methods_by_name['CheckPermissions']._serialized_options = b'\222\265\030\002\010\001\202\323\344\223\002\032\"\025/v1/check_permissions:\001*' + _globals['_AUTHORIZERSERVICE'].methods_by_name['ListPermissions']._loaded_options = None + _globals['_AUTHORIZERSERVICE'].methods_by_name['ListPermissions']._serialized_options = b'\222\265\030\002\010\001\202\323\344\223\002\031\"\024/v1/list_permissions:\001*' + _globals['_SIGNUPREQUEST']._serialized_start=197 + _globals['_SIGNUPREQUEST']._serialized_end=804 + _globals['_LOGINREQUEST']._serialized_start=807 + _globals['_LOGINREQUEST']._serialized_end=1003 + _globals['_LOGOUTREQUEST']._serialized_start=1005 + _globals['_LOGOUTREQUEST']._serialized_end=1020 + _globals['_LOGOUTRESPONSE']._serialized_start=1022 + _globals['_LOGOUTRESPONSE']._serialized_end=1064 + _globals['_MAGICLINKLOGINREQUEST']._serialized_start=1067 + _globals['_MAGICLINKLOGINREQUEST']._serialized_end=1223 + _globals['_MAGICLINKLOGINRESPONSE']._serialized_start=1225 + _globals['_MAGICLINKLOGINRESPONSE']._serialized_end=1275 + _globals['_VERIFYEMAILREQUEST']._serialized_start=1277 + _globals['_VERIFYEMAILREQUEST']._serialized_end=1350 + _globals['_RESENDVERIFYEMAILREQUEST']._serialized_start=1352 + _globals['_RESENDVERIFYEMAILREQUEST']._serialized_end=1473 + _globals['_RESENDVERIFYEMAILRESPONSE']._serialized_start=1475 + _globals['_RESENDVERIFYEMAILRESPONSE']._serialized_end=1528 + _globals['_VERIFYOTPREQUEST']._serialized_start=1531 + _globals['_VERIFYOTPREQUEST']._serialized_end=1701 + _globals['_RESENDOTPREQUEST']._serialized_start=1703 + _globals['_RESENDOTPREQUEST']._serialized_end=1819 + _globals['_RESENDOTPRESPONSE']._serialized_start=1821 + _globals['_RESENDOTPRESPONSE']._serialized_end=1866 + _globals['_FORGOTPASSWORDREQUEST']._serialized_start=1869 + _globals['_FORGOTPASSWORDREQUEST']._serialized_end=2025 + _globals['_FORGOTPASSWORDRESPONSE']._serialized_start=2027 + _globals['_FORGOTPASSWORDRESPONSE']._serialized_end=2143 + _globals['_RESETPASSWORDREQUEST']._serialized_start=2146 + _globals['_RESETPASSWORDREQUEST']._serialized_end=2347 + _globals['_RESETPASSWORDRESPONSE']._serialized_start=2349 + _globals['_RESETPASSWORDRESPONSE']._serialized_end=2398 + _globals['_PROFILEREQUEST']._serialized_start=2400 + _globals['_PROFILEREQUEST']._serialized_end=2416 + _globals['_UPDATEPROFILEREQUEST']._serialized_start=2419 + _globals['_UPDATEPROFILEREQUEST']._serialized_end=3015 + _globals['_UPDATEPROFILERESPONSE']._serialized_start=3017 + _globals['_UPDATEPROFILERESPONSE']._serialized_end=3066 + _globals['_DEACTIVATEACCOUNTREQUEST']._serialized_start=3068 + _globals['_DEACTIVATEACCOUNTREQUEST']._serialized_end=3094 + _globals['_DEACTIVATEACCOUNTRESPONSE']._serialized_start=3096 + _globals['_DEACTIVATEACCOUNTRESPONSE']._serialized_end=3149 + _globals['_REVOKEREQUEST']._serialized_start=3151 + _globals['_REVOKEREQUEST']._serialized_end=3212 + _globals['_REVOKERESPONSE']._serialized_start=3214 + _globals['_REVOKERESPONSE']._serialized_end=3256 + _globals['_SESSIONREQUEST']._serialized_start=3259 + _globals['_SESSIONREQUEST']._serialized_end=3421 + _globals['_VALIDATEJWTTOKENREQUEST']._serialized_start=3424 + _globals['_VALIDATEJWTTOKENREQUEST']._serialized_end=3622 + _globals['_VALIDATEJWTTOKENRESPONSE']._serialized_start=3624 + _globals['_VALIDATEJWTTOKENRESPONSE']._serialized_end=3725 + _globals['_VALIDATESESSIONREQUEST']._serialized_start=3728 + _globals['_VALIDATESESSIONREQUEST']._serialized_end=3887 + _globals['_VALIDATESESSIONRESPONSE']._serialized_start=3889 + _globals['_VALIDATESESSIONRESPONSE']._serialized_end=3982 + _globals['_METAREQUEST']._serialized_start=3984 + _globals['_METAREQUEST']._serialized_end=3997 + _globals['_CHECKPERMISSIONSREQUEST']._serialized_start=3999 + _globals['_CHECKPERMISSIONSREQUEST']._serialized_end=4117 + _globals['_CHECKPERMISSIONSRESPONSE']._serialized_start=4119 + _globals['_CHECKPERMISSIONSRESPONSE']._serialized_end=4209 + _globals['_LISTPERMISSIONSREQUEST']._serialized_start=4211 + _globals['_LISTPERMISSIONSREQUEST']._serialized_end=4316 + _globals['_LISTPERMISSIONSRESPONSE']._serialized_start=4319 + _globals['_LISTPERMISSIONSRESPONSE']._serialized_end=4461 + _globals['_AUTHORIZERSERVICE']._serialized_start=4464 + _globals['_AUTHORIZERSERVICE']._serialized_end=6872 +# @@protoc_insertion_point(module_scope) diff --git a/src/authorizer/_grpc/authorizer/v1/authorizer_pb2_grpc.py b/src/authorizer/_grpc/authorizer/v1/authorizer_pb2_grpc.py new file mode 100644 index 0000000..be97a54 --- /dev/null +++ b/src/authorizer/_grpc/authorizer/v1/authorizer_pb2_grpc.py @@ -0,0 +1,937 @@ +# Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT! +"""Client and server classes corresponding to protobuf-defined services.""" +import grpc + +from authorizer._grpc.authorizer.v1 import authorizer_pb2 as authorizer_dot_v1_dot_authorizer__pb2 +from authorizer._grpc.authorizer.v1 import types_pb2 as authorizer_dot_v1_dot_types__pb2 + + +class AuthorizerServiceStub(object): + """=== Identity creation & authentication === + """ + + def __init__(self, channel): + """Constructor. + + Args: + channel: A grpc.Channel. + """ + self.Signup = channel.unary_unary( + '/authorizer.v1.AuthorizerService/Signup', + request_serializer=authorizer_dot_v1_dot_authorizer__pb2.SignupRequest.SerializeToString, + response_deserializer=authorizer_dot_v1_dot_types__pb2.AuthResponse.FromString, + _registered_method=True) + self.Login = channel.unary_unary( + '/authorizer.v1.AuthorizerService/Login', + request_serializer=authorizer_dot_v1_dot_authorizer__pb2.LoginRequest.SerializeToString, + response_deserializer=authorizer_dot_v1_dot_types__pb2.AuthResponse.FromString, + _registered_method=True) + self.Logout = channel.unary_unary( + '/authorizer.v1.AuthorizerService/Logout', + request_serializer=authorizer_dot_v1_dot_authorizer__pb2.LogoutRequest.SerializeToString, + response_deserializer=authorizer_dot_v1_dot_authorizer__pb2.LogoutResponse.FromString, + _registered_method=True) + self.MagicLinkLogin = channel.unary_unary( + '/authorizer.v1.AuthorizerService/MagicLinkLogin', + request_serializer=authorizer_dot_v1_dot_authorizer__pb2.MagicLinkLoginRequest.SerializeToString, + response_deserializer=authorizer_dot_v1_dot_authorizer__pb2.MagicLinkLoginResponse.FromString, + _registered_method=True) + self.VerifyEmail = channel.unary_unary( + '/authorizer.v1.AuthorizerService/VerifyEmail', + request_serializer=authorizer_dot_v1_dot_authorizer__pb2.VerifyEmailRequest.SerializeToString, + response_deserializer=authorizer_dot_v1_dot_types__pb2.AuthResponse.FromString, + _registered_method=True) + self.ResendVerifyEmail = channel.unary_unary( + '/authorizer.v1.AuthorizerService/ResendVerifyEmail', + request_serializer=authorizer_dot_v1_dot_authorizer__pb2.ResendVerifyEmailRequest.SerializeToString, + response_deserializer=authorizer_dot_v1_dot_authorizer__pb2.ResendVerifyEmailResponse.FromString, + _registered_method=True) + self.VerifyOtp = channel.unary_unary( + '/authorizer.v1.AuthorizerService/VerifyOtp', + request_serializer=authorizer_dot_v1_dot_authorizer__pb2.VerifyOtpRequest.SerializeToString, + response_deserializer=authorizer_dot_v1_dot_types__pb2.AuthResponse.FromString, + _registered_method=True) + self.ResendOtp = channel.unary_unary( + '/authorizer.v1.AuthorizerService/ResendOtp', + request_serializer=authorizer_dot_v1_dot_authorizer__pb2.ResendOtpRequest.SerializeToString, + response_deserializer=authorizer_dot_v1_dot_authorizer__pb2.ResendOtpResponse.FromString, + _registered_method=True) + self.ForgotPassword = channel.unary_unary( + '/authorizer.v1.AuthorizerService/ForgotPassword', + request_serializer=authorizer_dot_v1_dot_authorizer__pb2.ForgotPasswordRequest.SerializeToString, + response_deserializer=authorizer_dot_v1_dot_authorizer__pb2.ForgotPasswordResponse.FromString, + _registered_method=True) + self.ResetPassword = channel.unary_unary( + '/authorizer.v1.AuthorizerService/ResetPassword', + request_serializer=authorizer_dot_v1_dot_authorizer__pb2.ResetPasswordRequest.SerializeToString, + response_deserializer=authorizer_dot_v1_dot_authorizer__pb2.ResetPasswordResponse.FromString, + _registered_method=True) + self.Profile = channel.unary_unary( + '/authorizer.v1.AuthorizerService/Profile', + request_serializer=authorizer_dot_v1_dot_authorizer__pb2.ProfileRequest.SerializeToString, + response_deserializer=authorizer_dot_v1_dot_types__pb2.User.FromString, + _registered_method=True) + self.UpdateProfile = channel.unary_unary( + '/authorizer.v1.AuthorizerService/UpdateProfile', + request_serializer=authorizer_dot_v1_dot_authorizer__pb2.UpdateProfileRequest.SerializeToString, + response_deserializer=authorizer_dot_v1_dot_authorizer__pb2.UpdateProfileResponse.FromString, + _registered_method=True) + self.DeactivateAccount = channel.unary_unary( + '/authorizer.v1.AuthorizerService/DeactivateAccount', + request_serializer=authorizer_dot_v1_dot_authorizer__pb2.DeactivateAccountRequest.SerializeToString, + response_deserializer=authorizer_dot_v1_dot_authorizer__pb2.DeactivateAccountResponse.FromString, + _registered_method=True) + self.Revoke = channel.unary_unary( + '/authorizer.v1.AuthorizerService/Revoke', + request_serializer=authorizer_dot_v1_dot_authorizer__pb2.RevokeRequest.SerializeToString, + response_deserializer=authorizer_dot_v1_dot_authorizer__pb2.RevokeResponse.FromString, + _registered_method=True) + self.Session = channel.unary_unary( + '/authorizer.v1.AuthorizerService/Session', + request_serializer=authorizer_dot_v1_dot_authorizer__pb2.SessionRequest.SerializeToString, + response_deserializer=authorizer_dot_v1_dot_types__pb2.AuthResponse.FromString, + _registered_method=True) + self.ValidateJwtToken = channel.unary_unary( + '/authorizer.v1.AuthorizerService/ValidateJwtToken', + request_serializer=authorizer_dot_v1_dot_authorizer__pb2.ValidateJwtTokenRequest.SerializeToString, + response_deserializer=authorizer_dot_v1_dot_authorizer__pb2.ValidateJwtTokenResponse.FromString, + _registered_method=True) + self.ValidateSession = channel.unary_unary( + '/authorizer.v1.AuthorizerService/ValidateSession', + request_serializer=authorizer_dot_v1_dot_authorizer__pb2.ValidateSessionRequest.SerializeToString, + response_deserializer=authorizer_dot_v1_dot_authorizer__pb2.ValidateSessionResponse.FromString, + _registered_method=True) + self.Meta = channel.unary_unary( + '/authorizer.v1.AuthorizerService/Meta', + request_serializer=authorizer_dot_v1_dot_authorizer__pb2.MetaRequest.SerializeToString, + response_deserializer=authorizer_dot_v1_dot_types__pb2.Meta.FromString, + _registered_method=True) + self.CheckPermissions = channel.unary_unary( + '/authorizer.v1.AuthorizerService/CheckPermissions', + request_serializer=authorizer_dot_v1_dot_authorizer__pb2.CheckPermissionsRequest.SerializeToString, + response_deserializer=authorizer_dot_v1_dot_authorizer__pb2.CheckPermissionsResponse.FromString, + _registered_method=True) + self.ListPermissions = channel.unary_unary( + '/authorizer.v1.AuthorizerService/ListPermissions', + request_serializer=authorizer_dot_v1_dot_authorizer__pb2.ListPermissionsRequest.SerializeToString, + response_deserializer=authorizer_dot_v1_dot_authorizer__pb2.ListPermissionsResponse.FromString, + _registered_method=True) + + +class AuthorizerServiceServicer(object): + """=== Identity creation & authentication === + """ + + def Signup(self, request, context): + """Signup registers a new user. Public; requires sign-up enabled in config. + Returns AuthResponse with tokens + (browser callers) Set-Cookie headers. + """ + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + def Login(self, request, context): + """Login authenticates with email/phone + password. + """ + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + def Logout(self, request, context): + """Logout ends the caller's current session. POST, not GET: logout mutates + server state (clears the session) and is audit-logged, so it must not be + a "safe" method per RFC 9110 §9.2.1 — GET would also expose it to CSRF. + """ + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + def MagicLinkLogin(self, request, context): + """MagicLinkLogin dispatches a passwordless email link. The clicked link + hits the existing /verify_email browser handler. + """ + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + def VerifyEmail(self, request, context): + """=== Email + OTP verification === + + """ + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + def ResendVerifyEmail(self, request, context): + """Missing associated documentation comment in .proto file.""" + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + def VerifyOtp(self, request, context): + """Missing associated documentation comment in .proto file.""" + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + def ResendOtp(self, request, context): + """Missing associated documentation comment in .proto file.""" + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + def ForgotPassword(self, request, context): + """=== Password lifecycle === + + """ + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + def ResetPassword(self, request, context): + """Missing associated documentation comment in .proto file.""" + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + def Profile(self, request, context): + """=== Profile + account === + + Profile returns the authenticated user. + """ + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + def UpdateProfile(self, request, context): + """Missing associated documentation comment in .proto file.""" + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + def DeactivateAccount(self, request, context): + """DeactivateAccount soft-deletes the caller's account and revokes all + refresh tokens as a side effect. OAuth has no concept of account + deactivation; this is the typed equivalent of SCIM PATCH active=false. + """ + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + def Revoke(self, request, context): + """=== Token + session === + + Revoke invalidates a refresh token. Typed mirror of RFC 7009. + """ + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + def Session(self, request, context): + """Session returns the AuthResponse bound to the caller's session cookie only. + NOT exposed as an MCP tool — SessionResponse carries access_token, + refresh_token, id_token, authenticator_secret, and recovery codes, + none of which should land in an LLM transcript. (Security audit C1.) + """ + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + def ValidateJwtToken(self, request, context): + """Missing associated documentation comment in .proto file.""" + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + def ValidateSession(self, request, context): + """Missing associated documentation comment in .proto file.""" + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + def Meta(self, request, context): + """=== Server discovery + caller authz === + + Meta returns server feature flags. No auth required. + """ + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + def CheckPermissions(self, request, context): + """CheckPermissions evaluates one or more fine-grained permission checks + ("does the subject have on ?") in a single call and + returns one result per check, in order. The subject defaults to the + authenticated caller; an explicit `user` is honored only for super-admins + or when it equals the caller's own subject. Fail-closed. + """ + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + def ListPermissions(self, request, context): + """ListPermissions enumerates what the subject can access. With both + `relation` and `object_type` set it answers "which s can I + ?"; either or both filters may be omitted to enumerate every + matching (type, relation) pair of the active model. Results are capped; + `truncated` reports when more permissions exist. Subject resolution + follows the same rules as CheckPermissions. + """ + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + +def add_AuthorizerServiceServicer_to_server(servicer, server): + rpc_method_handlers = { + 'Signup': grpc.unary_unary_rpc_method_handler( + servicer.Signup, + request_deserializer=authorizer_dot_v1_dot_authorizer__pb2.SignupRequest.FromString, + response_serializer=authorizer_dot_v1_dot_types__pb2.AuthResponse.SerializeToString, + ), + 'Login': grpc.unary_unary_rpc_method_handler( + servicer.Login, + request_deserializer=authorizer_dot_v1_dot_authorizer__pb2.LoginRequest.FromString, + response_serializer=authorizer_dot_v1_dot_types__pb2.AuthResponse.SerializeToString, + ), + 'Logout': grpc.unary_unary_rpc_method_handler( + servicer.Logout, + request_deserializer=authorizer_dot_v1_dot_authorizer__pb2.LogoutRequest.FromString, + response_serializer=authorizer_dot_v1_dot_authorizer__pb2.LogoutResponse.SerializeToString, + ), + 'MagicLinkLogin': grpc.unary_unary_rpc_method_handler( + servicer.MagicLinkLogin, + request_deserializer=authorizer_dot_v1_dot_authorizer__pb2.MagicLinkLoginRequest.FromString, + response_serializer=authorizer_dot_v1_dot_authorizer__pb2.MagicLinkLoginResponse.SerializeToString, + ), + 'VerifyEmail': grpc.unary_unary_rpc_method_handler( + servicer.VerifyEmail, + request_deserializer=authorizer_dot_v1_dot_authorizer__pb2.VerifyEmailRequest.FromString, + response_serializer=authorizer_dot_v1_dot_types__pb2.AuthResponse.SerializeToString, + ), + 'ResendVerifyEmail': grpc.unary_unary_rpc_method_handler( + servicer.ResendVerifyEmail, + request_deserializer=authorizer_dot_v1_dot_authorizer__pb2.ResendVerifyEmailRequest.FromString, + response_serializer=authorizer_dot_v1_dot_authorizer__pb2.ResendVerifyEmailResponse.SerializeToString, + ), + 'VerifyOtp': grpc.unary_unary_rpc_method_handler( + servicer.VerifyOtp, + request_deserializer=authorizer_dot_v1_dot_authorizer__pb2.VerifyOtpRequest.FromString, + response_serializer=authorizer_dot_v1_dot_types__pb2.AuthResponse.SerializeToString, + ), + 'ResendOtp': grpc.unary_unary_rpc_method_handler( + servicer.ResendOtp, + request_deserializer=authorizer_dot_v1_dot_authorizer__pb2.ResendOtpRequest.FromString, + response_serializer=authorizer_dot_v1_dot_authorizer__pb2.ResendOtpResponse.SerializeToString, + ), + 'ForgotPassword': grpc.unary_unary_rpc_method_handler( + servicer.ForgotPassword, + request_deserializer=authorizer_dot_v1_dot_authorizer__pb2.ForgotPasswordRequest.FromString, + response_serializer=authorizer_dot_v1_dot_authorizer__pb2.ForgotPasswordResponse.SerializeToString, + ), + 'ResetPassword': grpc.unary_unary_rpc_method_handler( + servicer.ResetPassword, + request_deserializer=authorizer_dot_v1_dot_authorizer__pb2.ResetPasswordRequest.FromString, + response_serializer=authorizer_dot_v1_dot_authorizer__pb2.ResetPasswordResponse.SerializeToString, + ), + 'Profile': grpc.unary_unary_rpc_method_handler( + servicer.Profile, + request_deserializer=authorizer_dot_v1_dot_authorizer__pb2.ProfileRequest.FromString, + response_serializer=authorizer_dot_v1_dot_types__pb2.User.SerializeToString, + ), + 'UpdateProfile': grpc.unary_unary_rpc_method_handler( + servicer.UpdateProfile, + request_deserializer=authorizer_dot_v1_dot_authorizer__pb2.UpdateProfileRequest.FromString, + response_serializer=authorizer_dot_v1_dot_authorizer__pb2.UpdateProfileResponse.SerializeToString, + ), + 'DeactivateAccount': grpc.unary_unary_rpc_method_handler( + servicer.DeactivateAccount, + request_deserializer=authorizer_dot_v1_dot_authorizer__pb2.DeactivateAccountRequest.FromString, + response_serializer=authorizer_dot_v1_dot_authorizer__pb2.DeactivateAccountResponse.SerializeToString, + ), + 'Revoke': grpc.unary_unary_rpc_method_handler( + servicer.Revoke, + request_deserializer=authorizer_dot_v1_dot_authorizer__pb2.RevokeRequest.FromString, + response_serializer=authorizer_dot_v1_dot_authorizer__pb2.RevokeResponse.SerializeToString, + ), + 'Session': grpc.unary_unary_rpc_method_handler( + servicer.Session, + request_deserializer=authorizer_dot_v1_dot_authorizer__pb2.SessionRequest.FromString, + response_serializer=authorizer_dot_v1_dot_types__pb2.AuthResponse.SerializeToString, + ), + 'ValidateJwtToken': grpc.unary_unary_rpc_method_handler( + servicer.ValidateJwtToken, + request_deserializer=authorizer_dot_v1_dot_authorizer__pb2.ValidateJwtTokenRequest.FromString, + response_serializer=authorizer_dot_v1_dot_authorizer__pb2.ValidateJwtTokenResponse.SerializeToString, + ), + 'ValidateSession': grpc.unary_unary_rpc_method_handler( + servicer.ValidateSession, + request_deserializer=authorizer_dot_v1_dot_authorizer__pb2.ValidateSessionRequest.FromString, + response_serializer=authorizer_dot_v1_dot_authorizer__pb2.ValidateSessionResponse.SerializeToString, + ), + 'Meta': grpc.unary_unary_rpc_method_handler( + servicer.Meta, + request_deserializer=authorizer_dot_v1_dot_authorizer__pb2.MetaRequest.FromString, + response_serializer=authorizer_dot_v1_dot_types__pb2.Meta.SerializeToString, + ), + 'CheckPermissions': grpc.unary_unary_rpc_method_handler( + servicer.CheckPermissions, + request_deserializer=authorizer_dot_v1_dot_authorizer__pb2.CheckPermissionsRequest.FromString, + response_serializer=authorizer_dot_v1_dot_authorizer__pb2.CheckPermissionsResponse.SerializeToString, + ), + 'ListPermissions': grpc.unary_unary_rpc_method_handler( + servicer.ListPermissions, + request_deserializer=authorizer_dot_v1_dot_authorizer__pb2.ListPermissionsRequest.FromString, + response_serializer=authorizer_dot_v1_dot_authorizer__pb2.ListPermissionsResponse.SerializeToString, + ), + } + generic_handler = grpc.method_handlers_generic_handler( + 'authorizer.v1.AuthorizerService', rpc_method_handlers) + server.add_generic_rpc_handlers((generic_handler,)) + server.add_registered_method_handlers('authorizer.v1.AuthorizerService', rpc_method_handlers) + + + # This class is part of an EXPERIMENTAL API. +class AuthorizerService(object): + """=== Identity creation & authentication === + """ + + @staticmethod + def Signup(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary( + request, + target, + '/authorizer.v1.AuthorizerService/Signup', + authorizer_dot_v1_dot_authorizer__pb2.SignupRequest.SerializeToString, + authorizer_dot_v1_dot_types__pb2.AuthResponse.FromString, + options, + channel_credentials, + insecure, + call_credentials, + compression, + wait_for_ready, + timeout, + metadata, + _registered_method=True) + + @staticmethod + def Login(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary( + request, + target, + '/authorizer.v1.AuthorizerService/Login', + authorizer_dot_v1_dot_authorizer__pb2.LoginRequest.SerializeToString, + authorizer_dot_v1_dot_types__pb2.AuthResponse.FromString, + options, + channel_credentials, + insecure, + call_credentials, + compression, + wait_for_ready, + timeout, + metadata, + _registered_method=True) + + @staticmethod + def Logout(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary( + request, + target, + '/authorizer.v1.AuthorizerService/Logout', + authorizer_dot_v1_dot_authorizer__pb2.LogoutRequest.SerializeToString, + authorizer_dot_v1_dot_authorizer__pb2.LogoutResponse.FromString, + options, + channel_credentials, + insecure, + call_credentials, + compression, + wait_for_ready, + timeout, + metadata, + _registered_method=True) + + @staticmethod + def MagicLinkLogin(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary( + request, + target, + '/authorizer.v1.AuthorizerService/MagicLinkLogin', + authorizer_dot_v1_dot_authorizer__pb2.MagicLinkLoginRequest.SerializeToString, + authorizer_dot_v1_dot_authorizer__pb2.MagicLinkLoginResponse.FromString, + options, + channel_credentials, + insecure, + call_credentials, + compression, + wait_for_ready, + timeout, + metadata, + _registered_method=True) + + @staticmethod + def VerifyEmail(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary( + request, + target, + '/authorizer.v1.AuthorizerService/VerifyEmail', + authorizer_dot_v1_dot_authorizer__pb2.VerifyEmailRequest.SerializeToString, + authorizer_dot_v1_dot_types__pb2.AuthResponse.FromString, + options, + channel_credentials, + insecure, + call_credentials, + compression, + wait_for_ready, + timeout, + metadata, + _registered_method=True) + + @staticmethod + def ResendVerifyEmail(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary( + request, + target, + '/authorizer.v1.AuthorizerService/ResendVerifyEmail', + authorizer_dot_v1_dot_authorizer__pb2.ResendVerifyEmailRequest.SerializeToString, + authorizer_dot_v1_dot_authorizer__pb2.ResendVerifyEmailResponse.FromString, + options, + channel_credentials, + insecure, + call_credentials, + compression, + wait_for_ready, + timeout, + metadata, + _registered_method=True) + + @staticmethod + def VerifyOtp(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary( + request, + target, + '/authorizer.v1.AuthorizerService/VerifyOtp', + authorizer_dot_v1_dot_authorizer__pb2.VerifyOtpRequest.SerializeToString, + authorizer_dot_v1_dot_types__pb2.AuthResponse.FromString, + options, + channel_credentials, + insecure, + call_credentials, + compression, + wait_for_ready, + timeout, + metadata, + _registered_method=True) + + @staticmethod + def ResendOtp(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary( + request, + target, + '/authorizer.v1.AuthorizerService/ResendOtp', + authorizer_dot_v1_dot_authorizer__pb2.ResendOtpRequest.SerializeToString, + authorizer_dot_v1_dot_authorizer__pb2.ResendOtpResponse.FromString, + options, + channel_credentials, + insecure, + call_credentials, + compression, + wait_for_ready, + timeout, + metadata, + _registered_method=True) + + @staticmethod + def ForgotPassword(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary( + request, + target, + '/authorizer.v1.AuthorizerService/ForgotPassword', + authorizer_dot_v1_dot_authorizer__pb2.ForgotPasswordRequest.SerializeToString, + authorizer_dot_v1_dot_authorizer__pb2.ForgotPasswordResponse.FromString, + options, + channel_credentials, + insecure, + call_credentials, + compression, + wait_for_ready, + timeout, + metadata, + _registered_method=True) + + @staticmethod + def ResetPassword(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary( + request, + target, + '/authorizer.v1.AuthorizerService/ResetPassword', + authorizer_dot_v1_dot_authorizer__pb2.ResetPasswordRequest.SerializeToString, + authorizer_dot_v1_dot_authorizer__pb2.ResetPasswordResponse.FromString, + options, + channel_credentials, + insecure, + call_credentials, + compression, + wait_for_ready, + timeout, + metadata, + _registered_method=True) + + @staticmethod + def Profile(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary( + request, + target, + '/authorizer.v1.AuthorizerService/Profile', + authorizer_dot_v1_dot_authorizer__pb2.ProfileRequest.SerializeToString, + authorizer_dot_v1_dot_types__pb2.User.FromString, + options, + channel_credentials, + insecure, + call_credentials, + compression, + wait_for_ready, + timeout, + metadata, + _registered_method=True) + + @staticmethod + def UpdateProfile(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary( + request, + target, + '/authorizer.v1.AuthorizerService/UpdateProfile', + authorizer_dot_v1_dot_authorizer__pb2.UpdateProfileRequest.SerializeToString, + authorizer_dot_v1_dot_authorizer__pb2.UpdateProfileResponse.FromString, + options, + channel_credentials, + insecure, + call_credentials, + compression, + wait_for_ready, + timeout, + metadata, + _registered_method=True) + + @staticmethod + def DeactivateAccount(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary( + request, + target, + '/authorizer.v1.AuthorizerService/DeactivateAccount', + authorizer_dot_v1_dot_authorizer__pb2.DeactivateAccountRequest.SerializeToString, + authorizer_dot_v1_dot_authorizer__pb2.DeactivateAccountResponse.FromString, + options, + channel_credentials, + insecure, + call_credentials, + compression, + wait_for_ready, + timeout, + metadata, + _registered_method=True) + + @staticmethod + def Revoke(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary( + request, + target, + '/authorizer.v1.AuthorizerService/Revoke', + authorizer_dot_v1_dot_authorizer__pb2.RevokeRequest.SerializeToString, + authorizer_dot_v1_dot_authorizer__pb2.RevokeResponse.FromString, + options, + channel_credentials, + insecure, + call_credentials, + compression, + wait_for_ready, + timeout, + metadata, + _registered_method=True) + + @staticmethod + def Session(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary( + request, + target, + '/authorizer.v1.AuthorizerService/Session', + authorizer_dot_v1_dot_authorizer__pb2.SessionRequest.SerializeToString, + authorizer_dot_v1_dot_types__pb2.AuthResponse.FromString, + options, + channel_credentials, + insecure, + call_credentials, + compression, + wait_for_ready, + timeout, + metadata, + _registered_method=True) + + @staticmethod + def ValidateJwtToken(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary( + request, + target, + '/authorizer.v1.AuthorizerService/ValidateJwtToken', + authorizer_dot_v1_dot_authorizer__pb2.ValidateJwtTokenRequest.SerializeToString, + authorizer_dot_v1_dot_authorizer__pb2.ValidateJwtTokenResponse.FromString, + options, + channel_credentials, + insecure, + call_credentials, + compression, + wait_for_ready, + timeout, + metadata, + _registered_method=True) + + @staticmethod + def ValidateSession(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary( + request, + target, + '/authorizer.v1.AuthorizerService/ValidateSession', + authorizer_dot_v1_dot_authorizer__pb2.ValidateSessionRequest.SerializeToString, + authorizer_dot_v1_dot_authorizer__pb2.ValidateSessionResponse.FromString, + options, + channel_credentials, + insecure, + call_credentials, + compression, + wait_for_ready, + timeout, + metadata, + _registered_method=True) + + @staticmethod + def Meta(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary( + request, + target, + '/authorizer.v1.AuthorizerService/Meta', + authorizer_dot_v1_dot_authorizer__pb2.MetaRequest.SerializeToString, + authorizer_dot_v1_dot_types__pb2.Meta.FromString, + options, + channel_credentials, + insecure, + call_credentials, + compression, + wait_for_ready, + timeout, + metadata, + _registered_method=True) + + @staticmethod + def CheckPermissions(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary( + request, + target, + '/authorizer.v1.AuthorizerService/CheckPermissions', + authorizer_dot_v1_dot_authorizer__pb2.CheckPermissionsRequest.SerializeToString, + authorizer_dot_v1_dot_authorizer__pb2.CheckPermissionsResponse.FromString, + options, + channel_credentials, + insecure, + call_credentials, + compression, + wait_for_ready, + timeout, + metadata, + _registered_method=True) + + @staticmethod + def ListPermissions(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary( + request, + target, + '/authorizer.v1.AuthorizerService/ListPermissions', + authorizer_dot_v1_dot_authorizer__pb2.ListPermissionsRequest.SerializeToString, + authorizer_dot_v1_dot_authorizer__pb2.ListPermissionsResponse.FromString, + options, + channel_credentials, + insecure, + call_credentials, + compression, + wait_for_ready, + timeout, + metadata, + _registered_method=True) diff --git a/src/authorizer/_grpc/authorizer/v1/common_pb2.py b/src/authorizer/_grpc/authorizer/v1/common_pb2.py new file mode 100644 index 0000000..26c2f81 --- /dev/null +++ b/src/authorizer/_grpc/authorizer/v1/common_pb2.py @@ -0,0 +1,38 @@ +# -*- coding: utf-8 -*- +# Generated by the protocol buffer compiler. DO NOT EDIT! +# NO CHECKED-IN PROTOBUF GENCODE +# source: authorizer/v1/common.proto +# Protobuf Python Version: 5.27.3 +"""Generated protocol buffer code.""" +from google.protobuf import descriptor as _descriptor +from google.protobuf import descriptor_pool as _descriptor_pool +from google.protobuf import runtime_version as _runtime_version +from google.protobuf import symbol_database as _symbol_database +from google.protobuf.internal import builder as _builder +_runtime_version.ValidateProtobufRuntimeVersion( + _runtime_version.Domain.PUBLIC, + 5, + 27, + 3, + '', + 'authorizer/v1/common.proto' +) +# @@protoc_insertion_point(imports) + +_sym_db = _symbol_database.Default() + + +from google.protobuf import struct_pb2 as google_dot_protobuf_dot_struct__pb2 + + +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x1a\x61uthorizer/v1/common.proto\x12\rauthorizer.v1\x1a\x1cgoogle/protobuf/struct.proto\"8\n\x07\x41ppData\x12-\n\x05value\x18\x01 \x01(\x0b\x32\x17.google.protobuf.StructR\x05valueB\xc7\x01\n\x11\x63om.authorizer.v1B\x0b\x43ommonProtoP\x01ZPgithub.com/authorizerdev/authorizer-go/internal/genpb/authorizer/v1;authorizerv1\xa2\x02\x03\x41XX\xaa\x02\rAuthorizer.V1\xca\x02\rAuthorizer\\V1\xe2\x02\x19\x41uthorizer\\V1\\GPBMetadata\xea\x02\x0e\x41uthorizer::V1b\x06proto3') + +_globals = globals() +_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) +_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'authorizer.v1.common_pb2', _globals) +if not _descriptor._USE_C_DESCRIPTORS: + _globals['DESCRIPTOR']._loaded_options = None + _globals['DESCRIPTOR']._serialized_options = b'\n\021com.authorizer.v1B\013CommonProtoP\001ZPgithub.com/authorizerdev/authorizer-go/internal/genpb/authorizer/v1;authorizerv1\242\002\003AXX\252\002\rAuthorizer.V1\312\002\rAuthorizer\\V1\342\002\031Authorizer\\V1\\GPBMetadata\352\002\016Authorizer::V1' + _globals['_APPDATA']._serialized_start=75 + _globals['_APPDATA']._serialized_end=131 +# @@protoc_insertion_point(module_scope) diff --git a/src/authorizer/_grpc/authorizer/v1/common_pb2_grpc.py b/src/authorizer/_grpc/authorizer/v1/common_pb2_grpc.py new file mode 100644 index 0000000..2daafff --- /dev/null +++ b/src/authorizer/_grpc/authorizer/v1/common_pb2_grpc.py @@ -0,0 +1,4 @@ +# Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT! +"""Client and server classes corresponding to protobuf-defined services.""" +import grpc + diff --git a/src/authorizer/_grpc/authorizer/v1/errors_pb2.py b/src/authorizer/_grpc/authorizer/v1/errors_pb2.py new file mode 100644 index 0000000..b8f198b --- /dev/null +++ b/src/authorizer/_grpc/authorizer/v1/errors_pb2.py @@ -0,0 +1,37 @@ +# -*- coding: utf-8 -*- +# Generated by the protocol buffer compiler. DO NOT EDIT! +# NO CHECKED-IN PROTOBUF GENCODE +# source: authorizer/v1/errors.proto +# Protobuf Python Version: 5.27.3 +"""Generated protocol buffer code.""" +from google.protobuf import descriptor as _descriptor +from google.protobuf import descriptor_pool as _descriptor_pool +from google.protobuf import runtime_version as _runtime_version +from google.protobuf import symbol_database as _symbol_database +from google.protobuf.internal import builder as _builder +_runtime_version.ValidateProtobufRuntimeVersion( + _runtime_version.Domain.PUBLIC, + 5, + 27, + 3, + '', + 'authorizer/v1/errors.proto' +) +# @@protoc_insertion_point(imports) + +_sym_db = _symbol_database.Default() + + + + +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x1a\x61uthorizer/v1/errors.proto\x12\rauthorizer.v1*\x86\x03\n\x0b\x45rrorReason\x12\x1c\n\x18\x45RROR_REASON_UNSPECIFIED\x10\x00\x12$\n ERROR_REASON_INVALID_CREDENTIALS\x10\x01\x12\"\n\x1e\x45RROR_REASON_PERMISSION_DENIED\x10\x02\x12\x1a\n\x16\x45RROR_REASON_NOT_FOUND\x10\x03\x12\x1f\n\x1b\x45RROR_REASON_ALREADY_EXISTS\x10\x04\x12 \n\x1c\x45RROR_REASON_INVALID_REQUEST\x10\x05\x12&\n\"ERROR_REASON_VERIFICATION_REQUIRED\x10\x06\x12#\n\x1f\x45RROR_REASON_OPERATION_DISABLED\x10\x07\x12\x1d\n\x19\x45RROR_REASON_RATE_LIMITED\x10\x08\x12\x1e\n\x1a\x45RROR_REASON_TOKEN_EXPIRED\x10\t\x12$\n ERROR_REASON_ACCOUNT_DEACTIVATED\x10\nB\xc7\x01\n\x11\x63om.authorizer.v1B\x0b\x45rrorsProtoP\x01ZPgithub.com/authorizerdev/authorizer-go/internal/genpb/authorizer/v1;authorizerv1\xa2\x02\x03\x41XX\xaa\x02\rAuthorizer.V1\xca\x02\rAuthorizer\\V1\xe2\x02\x19\x41uthorizer\\V1\\GPBMetadata\xea\x02\x0e\x41uthorizer::V1b\x06proto3') + +_globals = globals() +_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) +_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'authorizer.v1.errors_pb2', _globals) +if not _descriptor._USE_C_DESCRIPTORS: + _globals['DESCRIPTOR']._loaded_options = None + _globals['DESCRIPTOR']._serialized_options = b'\n\021com.authorizer.v1B\013ErrorsProtoP\001ZPgithub.com/authorizerdev/authorizer-go/internal/genpb/authorizer/v1;authorizerv1\242\002\003AXX\252\002\rAuthorizer.V1\312\002\rAuthorizer\\V1\342\002\031Authorizer\\V1\\GPBMetadata\352\002\016Authorizer::V1' + _globals['_ERRORREASON']._serialized_start=46 + _globals['_ERRORREASON']._serialized_end=436 +# @@protoc_insertion_point(module_scope) diff --git a/src/authorizer/_grpc/authorizer/v1/errors_pb2_grpc.py b/src/authorizer/_grpc/authorizer/v1/errors_pb2_grpc.py new file mode 100644 index 0000000..2daafff --- /dev/null +++ b/src/authorizer/_grpc/authorizer/v1/errors_pb2_grpc.py @@ -0,0 +1,4 @@ +# Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT! +"""Client and server classes corresponding to protobuf-defined services.""" +import grpc + diff --git a/src/authorizer/_grpc/authorizer/v1/pagination_pb2.py b/src/authorizer/_grpc/authorizer/v1/pagination_pb2.py new file mode 100644 index 0000000..024adb5 --- /dev/null +++ b/src/authorizer/_grpc/authorizer/v1/pagination_pb2.py @@ -0,0 +1,44 @@ +# -*- coding: utf-8 -*- +# Generated by the protocol buffer compiler. DO NOT EDIT! +# NO CHECKED-IN PROTOBUF GENCODE +# source: authorizer/v1/pagination.proto +# Protobuf Python Version: 5.27.3 +"""Generated protocol buffer code.""" +from google.protobuf import descriptor as _descriptor +from google.protobuf import descriptor_pool as _descriptor_pool +from google.protobuf import runtime_version as _runtime_version +from google.protobuf import symbol_database as _symbol_database +from google.protobuf.internal import builder as _builder +_runtime_version.ValidateProtobufRuntimeVersion( + _runtime_version.Domain.PUBLIC, + 5, + 27, + 3, + '', + 'authorizer/v1/pagination.proto' +) +# @@protoc_insertion_point(imports) + +_sym_db = _symbol_database.Default() + + +from authorizer._grpc.buf.validate import validate_pb2 as buf_dot_validate_dot_validate__pb2 + + +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x1e\x61uthorizer/v1/pagination.proto\x12\rauthorizer.v1\x1a\x1b\x62uf/validate/validate.proto\"q\n\x11PaginationRequest\x12\x1b\n\x04page\x18\x01 \x01(\x03\x42\x07\xbaH\x04\"\x02(\x00R\x04page\x12 \n\x05limit\x18\x02 \x01(\x03\x42\n\xbaH\x07\"\x05\x18\xe8\x07(\x00R\x05limit\x12\x1d\n\npage_token\x18\x03 \x01(\tR\tpageToken\"\x8c\x01\n\nPagination\x12\x14\n\x05limit\x18\x01 \x01(\x03R\x05limit\x12\x12\n\x04page\x18\x02 \x01(\x03R\x04page\x12\x16\n\x06offset\x18\x03 \x01(\x03R\x06offset\x12\x14\n\x05total\x18\x04 \x01(\x03R\x05total\x12&\n\x0fnext_page_token\x18\x05 \x01(\tR\rnextPageTokenB\xcb\x01\n\x11\x63om.authorizer.v1B\x0fPaginationProtoP\x01ZPgithub.com/authorizerdev/authorizer-go/internal/genpb/authorizer/v1;authorizerv1\xa2\x02\x03\x41XX\xaa\x02\rAuthorizer.V1\xca\x02\rAuthorizer\\V1\xe2\x02\x19\x41uthorizer\\V1\\GPBMetadata\xea\x02\x0e\x41uthorizer::V1b\x06proto3') + +_globals = globals() +_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) +_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'authorizer.v1.pagination_pb2', _globals) +if not _descriptor._USE_C_DESCRIPTORS: + _globals['DESCRIPTOR']._loaded_options = None + _globals['DESCRIPTOR']._serialized_options = b'\n\021com.authorizer.v1B\017PaginationProtoP\001ZPgithub.com/authorizerdev/authorizer-go/internal/genpb/authorizer/v1;authorizerv1\242\002\003AXX\252\002\rAuthorizer.V1\312\002\rAuthorizer\\V1\342\002\031Authorizer\\V1\\GPBMetadata\352\002\016Authorizer::V1' + _globals['_PAGINATIONREQUEST'].fields_by_name['page']._loaded_options = None + _globals['_PAGINATIONREQUEST'].fields_by_name['page']._serialized_options = b'\272H\004\"\002(\000' + _globals['_PAGINATIONREQUEST'].fields_by_name['limit']._loaded_options = None + _globals['_PAGINATIONREQUEST'].fields_by_name['limit']._serialized_options = b'\272H\007\"\005\030\350\007(\000' + _globals['_PAGINATIONREQUEST']._serialized_start=78 + _globals['_PAGINATIONREQUEST']._serialized_end=191 + _globals['_PAGINATION']._serialized_start=194 + _globals['_PAGINATION']._serialized_end=334 +# @@protoc_insertion_point(module_scope) diff --git a/src/authorizer/_grpc/authorizer/v1/pagination_pb2_grpc.py b/src/authorizer/_grpc/authorizer/v1/pagination_pb2_grpc.py new file mode 100644 index 0000000..2daafff --- /dev/null +++ b/src/authorizer/_grpc/authorizer/v1/pagination_pb2_grpc.py @@ -0,0 +1,4 @@ +# Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT! +"""Client and server classes corresponding to protobuf-defined services.""" +import grpc + diff --git a/src/authorizer/_grpc/authorizer/v1/types_pb2.py b/src/authorizer/_grpc/authorizer/v1/types_pb2.py new file mode 100644 index 0000000..b57c8eb --- /dev/null +++ b/src/authorizer/_grpc/authorizer/v1/types_pb2.py @@ -0,0 +1,52 @@ +# -*- coding: utf-8 -*- +# Generated by the protocol buffer compiler. DO NOT EDIT! +# NO CHECKED-IN PROTOBUF GENCODE +# source: authorizer/v1/types.proto +# Protobuf Python Version: 5.27.3 +"""Generated protocol buffer code.""" +from google.protobuf import descriptor as _descriptor +from google.protobuf import descriptor_pool as _descriptor_pool +from google.protobuf import runtime_version as _runtime_version +from google.protobuf import symbol_database as _symbol_database +from google.protobuf.internal import builder as _builder +_runtime_version.ValidateProtobufRuntimeVersion( + _runtime_version.Domain.PUBLIC, + 5, + 27, + 3, + '', + 'authorizer/v1/types.proto' +) +# @@protoc_insertion_point(imports) + +_sym_db = _symbol_database.Default() + + +from authorizer._grpc.authorizer.v1 import common_pb2 as authorizer_dot_v1_dot_common__pb2 + + +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x19\x61uthorizer/v1/types.proto\x12\rauthorizer.v1\x1a\x1a\x61uthorizer/v1/common.proto\"\xc1\x05\n\x04User\x12\x0e\n\x02id\x18\x01 \x01(\tR\x02id\x12\x14\n\x05\x65mail\x18\x02 \x01(\tR\x05\x65mail\x12%\n\x0e\x65mail_verified\x18\x03 \x01(\x08R\remailVerified\x12%\n\x0esignup_methods\x18\x04 \x01(\tR\rsignupMethods\x12\x1d\n\ngiven_name\x18\x05 \x01(\tR\tgivenName\x12\x1f\n\x0b\x66\x61mily_name\x18\x06 \x01(\tR\nfamilyName\x12\x1f\n\x0bmiddle_name\x18\x07 \x01(\tR\nmiddleName\x12\x1a\n\x08nickname\x18\x08 \x01(\tR\x08nickname\x12-\n\x12preferred_username\x18\t \x01(\tR\x11preferredUsername\x12\x16\n\x06gender\x18\n \x01(\tR\x06gender\x12\x1c\n\tbirthdate\x18\x0b \x01(\tR\tbirthdate\x12!\n\x0cphone_number\x18\x0c \x01(\tR\x0bphoneNumber\x12\x32\n\x15phone_number_verified\x18\r \x01(\x08R\x13phoneNumberVerified\x12\x18\n\x07picture\x18\x0e \x01(\tR\x07picture\x12\x14\n\x05roles\x18\x0f \x03(\tR\x05roles\x12\x1d\n\ncreated_at\x18\x10 \x01(\x03R\tcreatedAt\x12\x1d\n\nupdated_at\x18\x11 \x01(\x03R\tupdatedAt\x12+\n\x11revoked_timestamp\x18\x12 \x01(\x03R\x10revokedTimestamp\x12>\n\x1cis_multi_factor_auth_enabled\x18\x13 \x01(\x08R\x18isMultiFactorAuthEnabled\x12\x31\n\x08\x61pp_data\x18\x14 \x01(\x0b\x32\x16.authorizer.v1.AppDataR\x07\x61ppData\"\xc1\x04\n\x0c\x41uthResponse\x12\x18\n\x07message\x18\x01 \x01(\tR\x07message\x12>\n\x1cshould_show_email_otp_screen\x18\x02 \x01(\x08R\x18shouldShowEmailOtpScreen\x12@\n\x1dshould_show_mobile_otp_screen\x18\x03 \x01(\x08R\x19shouldShowMobileOtpScreen\x12\x35\n\x17should_show_totp_screen\x18\x04 \x01(\x08R\x14shouldShowTotpScreen\x12!\n\x0c\x61\x63\x63\x65ss_token\x18\x05 \x01(\tR\x0b\x61\x63\x63\x65ssToken\x12\x19\n\x08id_token\x18\x06 \x01(\tR\x07idToken\x12#\n\rrefresh_token\x18\x07 \x01(\tR\x0crefreshToken\x12\x1d\n\nexpires_in\x18\x08 \x01(\x03R\texpiresIn\x12\'\n\x04user\x18\t \x01(\x0b\x32\x13.authorizer.v1.UserR\x04user\x12>\n\x1b\x61uthenticator_scanner_image\x18\n \x01(\tR\x19\x61uthenticatorScannerImage\x12\x31\n\x14\x61uthenticator_secret\x18\x0b \x01(\tR\x13\x61uthenticatorSecret\x12@\n\x1c\x61uthenticator_recovery_codes\x18\x0c \x03(\tR\x1a\x61uthenticatorRecoveryCodes\"@\n\nPermission\x12\x16\n\x06object\x18\x01 \x01(\tR\x06object\x12\x1a\n\x08relation\x18\x02 \x01(\tR\x08relation\"F\n\x10\x46gaRelationInput\x12\x1a\n\x08relation\x18\x01 \x01(\tR\x08relation\x12\x16\n\x06object\x18\x02 \x01(\tR\x06object\"W\n\rFgaTupleInput\x12\x12\n\x04user\x18\x01 \x01(\tR\x04user\x12\x1a\n\x08relation\x18\x02 \x01(\tR\x08relation\x12\x16\n\x06object\x18\x03 \x01(\tR\x06object\"\x95\x01\n\x14PermissionCheckInput\x12\x1a\n\x08relation\x18\x01 \x01(\tR\x08relation\x12\x16\n\x06object\x18\x02 \x01(\tR\x06object\x12I\n\x11\x63ontextual_tuples\x18\x03 \x03(\x0b\x32\x1c.authorizer.v1.FgaTupleInputR\x10\x63ontextualTuples\"e\n\x15PermissionCheckResult\x12\x1a\n\x08relation\x18\x01 \x01(\tR\x08relation\x12\x16\n\x06object\x18\x02 \x01(\tR\x06object\x12\x18\n\x07\x61llowed\x18\x03 \x01(\x08R\x07\x61llowed\"\xfc\x08\n\x04Meta\x12\x18\n\x07version\x18\x01 \x01(\tR\x07version\x12\x1b\n\tclient_id\x18\x02 \x01(\tR\x08\x63lientId\x12\x35\n\x17is_google_login_enabled\x18\x03 \x01(\x08R\x14isGoogleLoginEnabled\x12\x39\n\x19is_facebook_login_enabled\x18\x04 \x01(\x08R\x16isFacebookLoginEnabled\x12\x35\n\x17is_github_login_enabled\x18\x05 \x01(\x08R\x14isGithubLoginEnabled\x12\x39\n\x19is_linkedin_login_enabled\x18\x06 \x01(\x08R\x16isLinkedinLoginEnabled\x12\x33\n\x16is_apple_login_enabled\x18\x07 \x01(\x08R\x13isAppleLoginEnabled\x12\x37\n\x18is_discord_login_enabled\x18\x08 \x01(\x08R\x15isDiscordLoginEnabled\x12\x37\n\x18is_twitter_login_enabled\x18\t \x01(\x08R\x15isTwitterLoginEnabled\x12;\n\x1ais_microsoft_login_enabled\x18\n \x01(\x08R\x17isMicrosoftLoginEnabled\x12\x35\n\x17is_twitch_login_enabled\x18\x0b \x01(\x08R\x14isTwitchLoginEnabled\x12\x35\n\x17is_roblox_login_enabled\x18\x0c \x01(\x08R\x14isRobloxLoginEnabled\x12\x41\n\x1dis_email_verification_enabled\x18\r \x01(\x08R\x1aisEmailVerificationEnabled\x12\x45\n\x1fis_basic_authentication_enabled\x18\x0e \x01(\x08R\x1cisBasicAuthenticationEnabled\x12<\n\x1bis_magic_link_login_enabled\x18\x0f \x01(\x08R\x17isMagicLinkLoginEnabled\x12+\n\x12is_sign_up_enabled\x18\x10 \x01(\x08R\x0fisSignUpEnabled\x12;\n\x1ais_strong_password_enabled\x18\x11 \x01(\x08R\x17isStrongPasswordEnabled\x12>\n\x1cis_multi_factor_auth_enabled\x18\x12 \x01(\x08R\x18isMultiFactorAuthEnabled\x12R\n&is_mobile_basic_authentication_enabled\x18\x13 \x01(\x08R\"isMobileBasicAuthenticationEnabled\x12\x41\n\x1dis_phone_verification_enabled\x18\x14 \x01(\x08R\x1aisPhoneVerificationEnabledB\xc6\x01\n\x11\x63om.authorizer.v1B\nTypesProtoP\x01ZPgithub.com/authorizerdev/authorizer-go/internal/genpb/authorizer/v1;authorizerv1\xa2\x02\x03\x41XX\xaa\x02\rAuthorizer.V1\xca\x02\rAuthorizer\\V1\xe2\x02\x19\x41uthorizer\\V1\\GPBMetadata\xea\x02\x0e\x41uthorizer::V1b\x06proto3') + +_globals = globals() +_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) +_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'authorizer.v1.types_pb2', _globals) +if not _descriptor._USE_C_DESCRIPTORS: + _globals['DESCRIPTOR']._loaded_options = None + _globals['DESCRIPTOR']._serialized_options = b'\n\021com.authorizer.v1B\nTypesProtoP\001ZPgithub.com/authorizerdev/authorizer-go/internal/genpb/authorizer/v1;authorizerv1\242\002\003AXX\252\002\rAuthorizer.V1\312\002\rAuthorizer\\V1\342\002\031Authorizer\\V1\\GPBMetadata\352\002\016Authorizer::V1' + _globals['_USER']._serialized_start=73 + _globals['_USER']._serialized_end=778 + _globals['_AUTHRESPONSE']._serialized_start=781 + _globals['_AUTHRESPONSE']._serialized_end=1358 + _globals['_PERMISSION']._serialized_start=1360 + _globals['_PERMISSION']._serialized_end=1424 + _globals['_FGARELATIONINPUT']._serialized_start=1426 + _globals['_FGARELATIONINPUT']._serialized_end=1496 + _globals['_FGATUPLEINPUT']._serialized_start=1498 + _globals['_FGATUPLEINPUT']._serialized_end=1585 + _globals['_PERMISSIONCHECKINPUT']._serialized_start=1588 + _globals['_PERMISSIONCHECKINPUT']._serialized_end=1737 + _globals['_PERMISSIONCHECKRESULT']._serialized_start=1739 + _globals['_PERMISSIONCHECKRESULT']._serialized_end=1840 + _globals['_META']._serialized_start=1843 + _globals['_META']._serialized_end=2991 +# @@protoc_insertion_point(module_scope) diff --git a/src/authorizer/_grpc/authorizer/v1/types_pb2_grpc.py b/src/authorizer/_grpc/authorizer/v1/types_pb2_grpc.py new file mode 100644 index 0000000..2daafff --- /dev/null +++ b/src/authorizer/_grpc/authorizer/v1/types_pb2_grpc.py @@ -0,0 +1,4 @@ +# Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT! +"""Client and server classes corresponding to protobuf-defined services.""" +import grpc + diff --git a/src/authorizer/_grpc/buf/__init__.py b/src/authorizer/_grpc/buf/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/authorizer/_grpc/buf/validate/__init__.py b/src/authorizer/_grpc/buf/validate/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/authorizer/_grpc/buf/validate/validate_pb2.py b/src/authorizer/_grpc/buf/validate/validate_pb2.py new file mode 100644 index 0000000..9c4e043 --- /dev/null +++ b/src/authorizer/_grpc/buf/validate/validate_pb2.py @@ -0,0 +1,469 @@ +# -*- coding: utf-8 -*- +# Generated by the protocol buffer compiler. DO NOT EDIT! +# NO CHECKED-IN PROTOBUF GENCODE +# source: buf/validate/validate.proto +# Protobuf Python Version: 5.27.3 +"""Generated protocol buffer code.""" +from google.protobuf import descriptor as _descriptor +from google.protobuf import descriptor_pool as _descriptor_pool +from google.protobuf import runtime_version as _runtime_version +from google.protobuf import symbol_database as _symbol_database +from google.protobuf.internal import builder as _builder +_runtime_version.ValidateProtobufRuntimeVersion( + _runtime_version.Domain.PUBLIC, + 5, + 27, + 3, + '', + 'buf/validate/validate.proto' +) +# @@protoc_insertion_point(imports) + +_sym_db = _symbol_database.Default() + + +from google.protobuf import descriptor_pb2 as google_dot_protobuf_dot_descriptor__pb2 +from google.protobuf import duration_pb2 as google_dot_protobuf_dot_duration__pb2 +from google.protobuf import field_mask_pb2 as google_dot_protobuf_dot_field__mask__pb2 +from google.protobuf import timestamp_pb2 as google_dot_protobuf_dot_timestamp__pb2 + + +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x1b\x62uf/validate/validate.proto\x12\x0c\x62uf.validate\x1a google/protobuf/descriptor.proto\x1a\x1egoogle/protobuf/duration.proto\x1a google/protobuf/field_mask.proto\x1a\x1fgoogle/protobuf/timestamp.proto\"P\n\x04Rule\x12\x0e\n\x02id\x18\x01 \x01(\tR\x02id\x12\x18\n\x07message\x18\x02 \x01(\tR\x07message\x12\x1e\n\nexpression\x18\x03 \x01(\tR\nexpression\"\xa1\x01\n\x0cMessageRules\x12%\n\x0e\x63\x65l_expression\x18\x05 \x03(\tR\rcelExpression\x12$\n\x03\x63\x65l\x18\x03 \x03(\x0b\x32\x12.buf.validate.RuleR\x03\x63\x65l\x12\x34\n\x05oneof\x18\x04 \x03(\x0b\x32\x1e.buf.validate.MessageOneofRuleR\x05oneofJ\x04\x08\x01\x10\x02R\x08\x64isabled\"F\n\x10MessageOneofRule\x12\x16\n\x06\x66ields\x18\x01 \x03(\tR\x06\x66ields\x12\x1a\n\x08required\x18\x02 \x01(\x08R\x08required\"(\n\nOneofRules\x12\x1a\n\x08required\x18\x01 \x01(\x08R\x08required\"\xe3\n\n\nFieldRules\x12%\n\x0e\x63\x65l_expression\x18\x1d \x03(\tR\rcelExpression\x12$\n\x03\x63\x65l\x18\x17 \x03(\x0b\x32\x12.buf.validate.RuleR\x03\x63\x65l\x12\x1a\n\x08required\x18\x19 \x01(\x08R\x08required\x12,\n\x06ignore\x18\x1b \x01(\x0e\x32\x14.buf.validate.IgnoreR\x06ignore\x12\x30\n\x05\x66loat\x18\x01 \x01(\x0b\x32\x18.buf.validate.FloatRulesH\x00R\x05\x66loat\x12\x33\n\x06\x64ouble\x18\x02 \x01(\x0b\x32\x19.buf.validate.DoubleRulesH\x00R\x06\x64ouble\x12\x30\n\x05int32\x18\x03 \x01(\x0b\x32\x18.buf.validate.Int32RulesH\x00R\x05int32\x12\x30\n\x05int64\x18\x04 \x01(\x0b\x32\x18.buf.validate.Int64RulesH\x00R\x05int64\x12\x33\n\x06uint32\x18\x05 \x01(\x0b\x32\x19.buf.validate.UInt32RulesH\x00R\x06uint32\x12\x33\n\x06uint64\x18\x06 \x01(\x0b\x32\x19.buf.validate.UInt64RulesH\x00R\x06uint64\x12\x33\n\x06sint32\x18\x07 \x01(\x0b\x32\x19.buf.validate.SInt32RulesH\x00R\x06sint32\x12\x33\n\x06sint64\x18\x08 \x01(\x0b\x32\x19.buf.validate.SInt64RulesH\x00R\x06sint64\x12\x36\n\x07\x66ixed32\x18\t \x01(\x0b\x32\x1a.buf.validate.Fixed32RulesH\x00R\x07\x66ixed32\x12\x36\n\x07\x66ixed64\x18\n \x01(\x0b\x32\x1a.buf.validate.Fixed64RulesH\x00R\x07\x66ixed64\x12\x39\n\x08sfixed32\x18\x0b \x01(\x0b\x32\x1b.buf.validate.SFixed32RulesH\x00R\x08sfixed32\x12\x39\n\x08sfixed64\x18\x0c \x01(\x0b\x32\x1b.buf.validate.SFixed64RulesH\x00R\x08sfixed64\x12-\n\x04\x62ool\x18\r \x01(\x0b\x32\x17.buf.validate.BoolRulesH\x00R\x04\x62ool\x12\x33\n\x06string\x18\x0e \x01(\x0b\x32\x19.buf.validate.StringRulesH\x00R\x06string\x12\x30\n\x05\x62ytes\x18\x0f \x01(\x0b\x32\x18.buf.validate.BytesRulesH\x00R\x05\x62ytes\x12-\n\x04\x65num\x18\x10 \x01(\x0b\x32\x17.buf.validate.EnumRulesH\x00R\x04\x65num\x12\x39\n\x08repeated\x18\x12 \x01(\x0b\x32\x1b.buf.validate.RepeatedRulesH\x00R\x08repeated\x12*\n\x03map\x18\x13 \x01(\x0b\x32\x16.buf.validate.MapRulesH\x00R\x03map\x12*\n\x03\x61ny\x18\x14 \x01(\x0b\x32\x16.buf.validate.AnyRulesH\x00R\x03\x61ny\x12\x39\n\x08\x64uration\x18\x15 \x01(\x0b\x32\x1b.buf.validate.DurationRulesH\x00R\x08\x64uration\x12=\n\nfield_mask\x18\x1c \x01(\x0b\x32\x1c.buf.validate.FieldMaskRulesH\x00R\tfieldMask\x12<\n\ttimestamp\x18\x16 \x01(\x0b\x32\x1c.buf.validate.TimestampRulesH\x00R\ttimestampB\x06\n\x04typeJ\x04\x08\x18\x10\x19J\x04\x08\x1a\x10\x1bR\x07skippedR\x0cignore_empty\"Z\n\x0fPredefinedRules\x12$\n\x03\x63\x65l\x18\x01 \x03(\x0b\x32\x12.buf.validate.RuleR\x03\x63\x65lJ\x04\x08\x18\x10\x19J\x04\x08\x1a\x10\x1bR\x07skippedR\x0cignore_empty\"\xae\x17\n\nFloatRules\x12\x84\x01\n\x05\x63onst\x18\x01 \x01(\x02\x42n\xc2Hk\ni\n\x0b\x66loat.const\x1aZthis != getField(rules, \'const\') ? \'must equal %s\'.format([getField(rules, \'const\')]) : \'\'R\x05\x63onst\x12\x9d\x01\n\x02lt\x18\x02 \x01(\x02\x42\x8a\x01\xc2H\x86\x01\n\x83\x01\n\x08\x66loat.lt\x1aw!has(rules.gte) && !has(rules.gt) && (this.isNan() || this >= rules.lt)? \'must be less than %s\'.format([rules.lt]) : \'\'H\x00R\x02lt\x12\xae\x01\n\x03lte\x18\x03 \x01(\x02\x42\x99\x01\xc2H\x95\x01\n\x92\x01\n\tfloat.lte\x1a\x84\x01!has(rules.gte) && !has(rules.gt) && (this.isNan() || this > rules.lte)? \'must be less than or equal to %s\'.format([rules.lte]) : \'\'H\x00R\x03lte\x12\xd4\x07\n\x02gt\x18\x04 \x01(\x02\x42\xc1\x07\xc2H\xbd\x07\n\x86\x01\n\x08\x66loat.gt\x1az!has(rules.lt) && !has(rules.lte) && (this.isNan() || this <= rules.gt)? \'must be greater than %s\'.format([rules.gt]) : \'\'\n\xbd\x01\n\x0b\x66loat.gt_lt\x1a\xad\x01has(rules.lt) && rules.lt >= rules.gt && (this.isNan() || this >= rules.lt || this <= rules.gt)? \'must be greater than %s and less than %s\'.format([rules.gt, rules.lt]) : \'\'\n\xc7\x01\n\x15\x66loat.gt_lt_exclusive\x1a\xad\x01has(rules.lt) && rules.lt < rules.gt && (this.isNan() || (rules.lt <= this && this <= rules.gt))? \'must be greater than %s or less than %s\'.format([rules.gt, rules.lt]) : \'\'\n\xcd\x01\n\x0c\x66loat.gt_lte\x1a\xbc\x01has(rules.lte) && rules.lte >= rules.gt && (this.isNan() || this > rules.lte || this <= rules.gt)? \'must be greater than %s and less than or equal to %s\'.format([rules.gt, rules.lte]) : \'\'\n\xd7\x01\n\x16\x66loat.gt_lte_exclusive\x1a\xbc\x01has(rules.lte) && rules.lte < rules.gt && (this.isNan() || (rules.lte < this && this <= rules.gt))? \'must be greater than %s or less than or equal to %s\'.format([rules.gt, rules.lte]) : \'\'H\x01R\x02gt\x12\xa1\x08\n\x03gte\x18\x05 \x01(\x02\x42\x8c\x08\xc2H\x88\x08\n\x95\x01\n\tfloat.gte\x1a\x87\x01!has(rules.lt) && !has(rules.lte) && (this.isNan() || this < rules.gte)? \'must be greater than or equal to %s\'.format([rules.gte]) : \'\'\n\xcc\x01\n\x0c\x66loat.gte_lt\x1a\xbb\x01has(rules.lt) && rules.lt >= rules.gte && (this.isNan() || this >= rules.lt || this < rules.gte)? \'must be greater than or equal to %s and less than %s\'.format([rules.gte, rules.lt]) : \'\'\n\xd6\x01\n\x16\x66loat.gte_lt_exclusive\x1a\xbb\x01has(rules.lt) && rules.lt < rules.gte && (this.isNan() || (rules.lt <= this && this < rules.gte))? \'must be greater than or equal to %s or less than %s\'.format([rules.gte, rules.lt]) : \'\'\n\xdc\x01\n\rfloat.gte_lte\x1a\xca\x01has(rules.lte) && rules.lte >= rules.gte && (this.isNan() || this > rules.lte || this < rules.gte)? \'must be greater than or equal to %s and less than or equal to %s\'.format([rules.gte, rules.lte]) : \'\'\n\xe6\x01\n\x17\x66loat.gte_lte_exclusive\x1a\xca\x01has(rules.lte) && rules.lte < rules.gte && (this.isNan() || (rules.lte < this && this < rules.gte))? \'must be greater than or equal to %s or less than or equal to %s\'.format([rules.gte, rules.lte]) : \'\'H\x01R\x03gte\x12}\n\x02in\x18\x06 \x03(\x02\x42m\xc2Hj\nh\n\x08\x66loat.in\x1a\\!(this in getField(rules, \'in\')) ? \'must be in list %s\'.format([getField(rules, \'in\')]) : \'\'R\x02in\x12w\n\x06not_in\x18\x07 \x03(\x02\x42`\xc2H]\n[\n\x0c\x66loat.not_in\x1aKthis in rules.not_in ? \'must not be in list %s\'.format([rules.not_in]) : \'\'R\x05notIn\x12w\n\x06\x66inite\x18\x08 \x01(\x08\x42_\xc2H\\\nZ\n\x0c\x66loat.finite\x1aJrules.finite ? (this.isNan() || this.isInf() ? \'must be finite\' : \'\') : \'\'R\x06\x66inite\x12\x34\n\x07\x65xample\x18\t \x03(\x02\x42\x1a\xc2H\x17\n\x15\n\rfloat.example\x1a\x04trueR\x07\x65xample*\t\x08\xe8\x07\x10\x80\x80\x80\x80\x02\x42\x0b\n\tless_thanB\x0e\n\x0cgreater_than\"\xc0\x17\n\x0b\x44oubleRules\x12\x85\x01\n\x05\x63onst\x18\x01 \x01(\x01\x42o\xc2Hl\nj\n\x0c\x64ouble.const\x1aZthis != getField(rules, \'const\') ? \'must equal %s\'.format([getField(rules, \'const\')]) : \'\'R\x05\x63onst\x12\x9e\x01\n\x02lt\x18\x02 \x01(\x01\x42\x8b\x01\xc2H\x87\x01\n\x84\x01\n\tdouble.lt\x1aw!has(rules.gte) && !has(rules.gt) && (this.isNan() || this >= rules.lt)? \'must be less than %s\'.format([rules.lt]) : \'\'H\x00R\x02lt\x12\xaf\x01\n\x03lte\x18\x03 \x01(\x01\x42\x9a\x01\xc2H\x96\x01\n\x93\x01\n\ndouble.lte\x1a\x84\x01!has(rules.gte) && !has(rules.gt) && (this.isNan() || this > rules.lte)? \'must be less than or equal to %s\'.format([rules.lte]) : \'\'H\x00R\x03lte\x12\xd9\x07\n\x02gt\x18\x04 \x01(\x01\x42\xc6\x07\xc2H\xc2\x07\n\x87\x01\n\tdouble.gt\x1az!has(rules.lt) && !has(rules.lte) && (this.isNan() || this <= rules.gt)? \'must be greater than %s\'.format([rules.gt]) : \'\'\n\xbe\x01\n\x0c\x64ouble.gt_lt\x1a\xad\x01has(rules.lt) && rules.lt >= rules.gt && (this.isNan() || this >= rules.lt || this <= rules.gt)? \'must be greater than %s and less than %s\'.format([rules.gt, rules.lt]) : \'\'\n\xc8\x01\n\x16\x64ouble.gt_lt_exclusive\x1a\xad\x01has(rules.lt) && rules.lt < rules.gt && (this.isNan() || (rules.lt <= this && this <= rules.gt))? \'must be greater than %s or less than %s\'.format([rules.gt, rules.lt]) : \'\'\n\xce\x01\n\rdouble.gt_lte\x1a\xbc\x01has(rules.lte) && rules.lte >= rules.gt && (this.isNan() || this > rules.lte || this <= rules.gt)? \'must be greater than %s and less than or equal to %s\'.format([rules.gt, rules.lte]) : \'\'\n\xd8\x01\n\x17\x64ouble.gt_lte_exclusive\x1a\xbc\x01has(rules.lte) && rules.lte < rules.gt && (this.isNan() || (rules.lte < this && this <= rules.gt))? \'must be greater than %s or less than or equal to %s\'.format([rules.gt, rules.lte]) : \'\'H\x01R\x02gt\x12\xa6\x08\n\x03gte\x18\x05 \x01(\x01\x42\x91\x08\xc2H\x8d\x08\n\x96\x01\n\ndouble.gte\x1a\x87\x01!has(rules.lt) && !has(rules.lte) && (this.isNan() || this < rules.gte)? \'must be greater than or equal to %s\'.format([rules.gte]) : \'\'\n\xcd\x01\n\rdouble.gte_lt\x1a\xbb\x01has(rules.lt) && rules.lt >= rules.gte && (this.isNan() || this >= rules.lt || this < rules.gte)? \'must be greater than or equal to %s and less than %s\'.format([rules.gte, rules.lt]) : \'\'\n\xd7\x01\n\x17\x64ouble.gte_lt_exclusive\x1a\xbb\x01has(rules.lt) && rules.lt < rules.gte && (this.isNan() || (rules.lt <= this && this < rules.gte))? \'must be greater than or equal to %s or less than %s\'.format([rules.gte, rules.lt]) : \'\'\n\xdd\x01\n\x0e\x64ouble.gte_lte\x1a\xca\x01has(rules.lte) && rules.lte >= rules.gte && (this.isNan() || this > rules.lte || this < rules.gte)? \'must be greater than or equal to %s and less than or equal to %s\'.format([rules.gte, rules.lte]) : \'\'\n\xe7\x01\n\x18\x64ouble.gte_lte_exclusive\x1a\xca\x01has(rules.lte) && rules.lte < rules.gte && (this.isNan() || (rules.lte < this && this < rules.gte))? \'must be greater than or equal to %s or less than or equal to %s\'.format([rules.gte, rules.lte]) : \'\'H\x01R\x03gte\x12~\n\x02in\x18\x06 \x03(\x01\x42n\xc2Hk\ni\n\tdouble.in\x1a\\!(this in getField(rules, \'in\')) ? \'must be in list %s\'.format([getField(rules, \'in\')]) : \'\'R\x02in\x12x\n\x06not_in\x18\x07 \x03(\x01\x42\x61\xc2H^\n\\\n\rdouble.not_in\x1aKthis in rules.not_in ? \'must not be in list %s\'.format([rules.not_in]) : \'\'R\x05notIn\x12x\n\x06\x66inite\x18\x08 \x01(\x08\x42`\xc2H]\n[\n\rdouble.finite\x1aJrules.finite ? (this.isNan() || this.isInf() ? \'must be finite\' : \'\') : \'\'R\x06\x66inite\x12\x35\n\x07\x65xample\x18\t \x03(\x01\x42\x1b\xc2H\x18\n\x16\n\x0e\x64ouble.example\x1a\x04trueR\x07\x65xample*\t\x08\xe8\x07\x10\x80\x80\x80\x80\x02\x42\x0b\n\tless_thanB\x0e\n\x0cgreater_than\"\xde\x14\n\nInt32Rules\x12\x84\x01\n\x05\x63onst\x18\x01 \x01(\x05\x42n\xc2Hk\ni\n\x0bint32.const\x1aZthis != getField(rules, \'const\') ? \'must equal %s\'.format([getField(rules, \'const\')]) : \'\'R\x05\x63onst\x12\x88\x01\n\x02lt\x18\x02 \x01(\x05\x42v\xc2Hs\nq\n\x08int32.lt\x1a\x65!has(rules.gte) && !has(rules.gt) && this >= rules.lt? \'must be less than %s\'.format([rules.lt]) : \'\'H\x00R\x02lt\x12\x9a\x01\n\x03lte\x18\x03 \x01(\x05\x42\x85\x01\xc2H\x81\x01\n\x7f\n\tint32.lte\x1ar!has(rules.gte) && !has(rules.gt) && this > rules.lte? \'must be less than or equal to %s\'.format([rules.lte]) : \'\'H\x00R\x03lte\x12\xfd\x06\n\x02gt\x18\x04 \x01(\x05\x42\xea\x06\xc2H\xe6\x06\nt\n\x08int32.gt\x1ah!has(rules.lt) && !has(rules.lte) && this <= rules.gt? \'must be greater than %s\'.format([rules.gt]) : \'\'\n\xad\x01\n\x0bint32.gt_lt\x1a\x9d\x01has(rules.lt) && rules.lt >= rules.gt && (this >= rules.lt || this <= rules.gt)? \'must be greater than %s and less than %s\'.format([rules.gt, rules.lt]) : \'\'\n\xb5\x01\n\x15int32.gt_lt_exclusive\x1a\x9b\x01has(rules.lt) && rules.lt < rules.gt && (rules.lt <= this && this <= rules.gt)? \'must be greater than %s or less than %s\'.format([rules.gt, rules.lt]) : \'\'\n\xbd\x01\n\x0cint32.gt_lte\x1a\xac\x01has(rules.lte) && rules.lte >= rules.gt && (this > rules.lte || this <= rules.gt)? \'must be greater than %s and less than or equal to %s\'.format([rules.gt, rules.lte]) : \'\'\n\xc5\x01\n\x16int32.gt_lte_exclusive\x1a\xaa\x01has(rules.lte) && rules.lte < rules.gt && (rules.lte < this && this <= rules.gt)? \'must be greater than %s or less than or equal to %s\'.format([rules.gt, rules.lte]) : \'\'H\x01R\x02gt\x12\xca\x07\n\x03gte\x18\x05 \x01(\x05\x42\xb5\x07\xc2H\xb1\x07\n\x82\x01\n\tint32.gte\x1au!has(rules.lt) && !has(rules.lte) && this < rules.gte? \'must be greater than or equal to %s\'.format([rules.gte]) : \'\'\n\xbc\x01\n\x0cint32.gte_lt\x1a\xab\x01has(rules.lt) && rules.lt >= rules.gte && (this >= rules.lt || this < rules.gte)? \'must be greater than or equal to %s and less than %s\'.format([rules.gte, rules.lt]) : \'\'\n\xc4\x01\n\x16int32.gte_lt_exclusive\x1a\xa9\x01has(rules.lt) && rules.lt < rules.gte && (rules.lt <= this && this < rules.gte)? \'must be greater than or equal to %s or less than %s\'.format([rules.gte, rules.lt]) : \'\'\n\xcc\x01\n\rint32.gte_lte\x1a\xba\x01has(rules.lte) && rules.lte >= rules.gte && (this > rules.lte || this < rules.gte)? \'must be greater than or equal to %s and less than or equal to %s\'.format([rules.gte, rules.lte]) : \'\'\n\xd4\x01\n\x17int32.gte_lte_exclusive\x1a\xb8\x01has(rules.lte) && rules.lte < rules.gte && (rules.lte < this && this < rules.gte)? \'must be greater than or equal to %s or less than or equal to %s\'.format([rules.gte, rules.lte]) : \'\'H\x01R\x03gte\x12}\n\x02in\x18\x06 \x03(\x05\x42m\xc2Hj\nh\n\x08int32.in\x1a\\!(this in getField(rules, \'in\')) ? \'must be in list %s\'.format([getField(rules, \'in\')]) : \'\'R\x02in\x12w\n\x06not_in\x18\x07 \x03(\x05\x42`\xc2H]\n[\n\x0cint32.not_in\x1aKthis in rules.not_in ? \'must not be in list %s\'.format([rules.not_in]) : \'\'R\x05notIn\x12\x34\n\x07\x65xample\x18\x08 \x03(\x05\x42\x1a\xc2H\x17\n\x15\n\rint32.example\x1a\x04trueR\x07\x65xample*\t\x08\xe8\x07\x10\x80\x80\x80\x80\x02\x42\x0b\n\tless_thanB\x0e\n\x0cgreater_than\"\xde\x14\n\nInt64Rules\x12\x84\x01\n\x05\x63onst\x18\x01 \x01(\x03\x42n\xc2Hk\ni\n\x0bint64.const\x1aZthis != getField(rules, \'const\') ? \'must equal %s\'.format([getField(rules, \'const\')]) : \'\'R\x05\x63onst\x12\x88\x01\n\x02lt\x18\x02 \x01(\x03\x42v\xc2Hs\nq\n\x08int64.lt\x1a\x65!has(rules.gte) && !has(rules.gt) && this >= rules.lt? \'must be less than %s\'.format([rules.lt]) : \'\'H\x00R\x02lt\x12\x9a\x01\n\x03lte\x18\x03 \x01(\x03\x42\x85\x01\xc2H\x81\x01\n\x7f\n\tint64.lte\x1ar!has(rules.gte) && !has(rules.gt) && this > rules.lte? \'must be less than or equal to %s\'.format([rules.lte]) : \'\'H\x00R\x03lte\x12\xfd\x06\n\x02gt\x18\x04 \x01(\x03\x42\xea\x06\xc2H\xe6\x06\nt\n\x08int64.gt\x1ah!has(rules.lt) && !has(rules.lte) && this <= rules.gt? \'must be greater than %s\'.format([rules.gt]) : \'\'\n\xad\x01\n\x0bint64.gt_lt\x1a\x9d\x01has(rules.lt) && rules.lt >= rules.gt && (this >= rules.lt || this <= rules.gt)? \'must be greater than %s and less than %s\'.format([rules.gt, rules.lt]) : \'\'\n\xb5\x01\n\x15int64.gt_lt_exclusive\x1a\x9b\x01has(rules.lt) && rules.lt < rules.gt && (rules.lt <= this && this <= rules.gt)? \'must be greater than %s or less than %s\'.format([rules.gt, rules.lt]) : \'\'\n\xbd\x01\n\x0cint64.gt_lte\x1a\xac\x01has(rules.lte) && rules.lte >= rules.gt && (this > rules.lte || this <= rules.gt)? \'must be greater than %s and less than or equal to %s\'.format([rules.gt, rules.lte]) : \'\'\n\xc5\x01\n\x16int64.gt_lte_exclusive\x1a\xaa\x01has(rules.lte) && rules.lte < rules.gt && (rules.lte < this && this <= rules.gt)? \'must be greater than %s or less than or equal to %s\'.format([rules.gt, rules.lte]) : \'\'H\x01R\x02gt\x12\xca\x07\n\x03gte\x18\x05 \x01(\x03\x42\xb5\x07\xc2H\xb1\x07\n\x82\x01\n\tint64.gte\x1au!has(rules.lt) && !has(rules.lte) && this < rules.gte? \'must be greater than or equal to %s\'.format([rules.gte]) : \'\'\n\xbc\x01\n\x0cint64.gte_lt\x1a\xab\x01has(rules.lt) && rules.lt >= rules.gte && (this >= rules.lt || this < rules.gte)? \'must be greater than or equal to %s and less than %s\'.format([rules.gte, rules.lt]) : \'\'\n\xc4\x01\n\x16int64.gte_lt_exclusive\x1a\xa9\x01has(rules.lt) && rules.lt < rules.gte && (rules.lt <= this && this < rules.gte)? \'must be greater than or equal to %s or less than %s\'.format([rules.gte, rules.lt]) : \'\'\n\xcc\x01\n\rint64.gte_lte\x1a\xba\x01has(rules.lte) && rules.lte >= rules.gte && (this > rules.lte || this < rules.gte)? \'must be greater than or equal to %s and less than or equal to %s\'.format([rules.gte, rules.lte]) : \'\'\n\xd4\x01\n\x17int64.gte_lte_exclusive\x1a\xb8\x01has(rules.lte) && rules.lte < rules.gte && (rules.lte < this && this < rules.gte)? \'must be greater than or equal to %s or less than or equal to %s\'.format([rules.gte, rules.lte]) : \'\'H\x01R\x03gte\x12}\n\x02in\x18\x06 \x03(\x03\x42m\xc2Hj\nh\n\x08int64.in\x1a\\!(this in getField(rules, \'in\')) ? \'must be in list %s\'.format([getField(rules, \'in\')]) : \'\'R\x02in\x12w\n\x06not_in\x18\x07 \x03(\x03\x42`\xc2H]\n[\n\x0cint64.not_in\x1aKthis in rules.not_in ? \'must not be in list %s\'.format([rules.not_in]) : \'\'R\x05notIn\x12\x34\n\x07\x65xample\x18\t \x03(\x03\x42\x1a\xc2H\x17\n\x15\n\rint64.example\x1a\x04trueR\x07\x65xample*\t\x08\xe8\x07\x10\x80\x80\x80\x80\x02\x42\x0b\n\tless_thanB\x0e\n\x0cgreater_than\"\xf0\x14\n\x0bUInt32Rules\x12\x85\x01\n\x05\x63onst\x18\x01 \x01(\rBo\xc2Hl\nj\n\x0cuint32.const\x1aZthis != getField(rules, \'const\') ? \'must equal %s\'.format([getField(rules, \'const\')]) : \'\'R\x05\x63onst\x12\x89\x01\n\x02lt\x18\x02 \x01(\rBw\xc2Ht\nr\n\tuint32.lt\x1a\x65!has(rules.gte) && !has(rules.gt) && this >= rules.lt? \'must be less than %s\'.format([rules.lt]) : \'\'H\x00R\x02lt\x12\x9c\x01\n\x03lte\x18\x03 \x01(\rB\x87\x01\xc2H\x83\x01\n\x80\x01\n\nuint32.lte\x1ar!has(rules.gte) && !has(rules.gt) && this > rules.lte? \'must be less than or equal to %s\'.format([rules.lte]) : \'\'H\x00R\x03lte\x12\x82\x07\n\x02gt\x18\x04 \x01(\rB\xef\x06\xc2H\xeb\x06\nu\n\tuint32.gt\x1ah!has(rules.lt) && !has(rules.lte) && this <= rules.gt? \'must be greater than %s\'.format([rules.gt]) : \'\'\n\xae\x01\n\x0cuint32.gt_lt\x1a\x9d\x01has(rules.lt) && rules.lt >= rules.gt && (this >= rules.lt || this <= rules.gt)? \'must be greater than %s and less than %s\'.format([rules.gt, rules.lt]) : \'\'\n\xb6\x01\n\x16uint32.gt_lt_exclusive\x1a\x9b\x01has(rules.lt) && rules.lt < rules.gt && (rules.lt <= this && this <= rules.gt)? \'must be greater than %s or less than %s\'.format([rules.gt, rules.lt]) : \'\'\n\xbe\x01\n\ruint32.gt_lte\x1a\xac\x01has(rules.lte) && rules.lte >= rules.gt && (this > rules.lte || this <= rules.gt)? \'must be greater than %s and less than or equal to %s\'.format([rules.gt, rules.lte]) : \'\'\n\xc6\x01\n\x17uint32.gt_lte_exclusive\x1a\xaa\x01has(rules.lte) && rules.lte < rules.gt && (rules.lte < this && this <= rules.gt)? \'must be greater than %s or less than or equal to %s\'.format([rules.gt, rules.lte]) : \'\'H\x01R\x02gt\x12\xcf\x07\n\x03gte\x18\x05 \x01(\rB\xba\x07\xc2H\xb6\x07\n\x83\x01\n\nuint32.gte\x1au!has(rules.lt) && !has(rules.lte) && this < rules.gte? \'must be greater than or equal to %s\'.format([rules.gte]) : \'\'\n\xbd\x01\n\ruint32.gte_lt\x1a\xab\x01has(rules.lt) && rules.lt >= rules.gte && (this >= rules.lt || this < rules.gte)? \'must be greater than or equal to %s and less than %s\'.format([rules.gte, rules.lt]) : \'\'\n\xc5\x01\n\x17uint32.gte_lt_exclusive\x1a\xa9\x01has(rules.lt) && rules.lt < rules.gte && (rules.lt <= this && this < rules.gte)? \'must be greater than or equal to %s or less than %s\'.format([rules.gte, rules.lt]) : \'\'\n\xcd\x01\n\x0euint32.gte_lte\x1a\xba\x01has(rules.lte) && rules.lte >= rules.gte && (this > rules.lte || this < rules.gte)? \'must be greater than or equal to %s and less than or equal to %s\'.format([rules.gte, rules.lte]) : \'\'\n\xd5\x01\n\x18uint32.gte_lte_exclusive\x1a\xb8\x01has(rules.lte) && rules.lte < rules.gte && (rules.lte < this && this < rules.gte)? \'must be greater than or equal to %s or less than or equal to %s\'.format([rules.gte, rules.lte]) : \'\'H\x01R\x03gte\x12~\n\x02in\x18\x06 \x03(\rBn\xc2Hk\ni\n\tuint32.in\x1a\\!(this in getField(rules, \'in\')) ? \'must be in list %s\'.format([getField(rules, \'in\')]) : \'\'R\x02in\x12x\n\x06not_in\x18\x07 \x03(\rBa\xc2H^\n\\\n\ruint32.not_in\x1aKthis in rules.not_in ? \'must not be in list %s\'.format([rules.not_in]) : \'\'R\x05notIn\x12\x35\n\x07\x65xample\x18\x08 \x03(\rB\x1b\xc2H\x18\n\x16\n\x0euint32.example\x1a\x04trueR\x07\x65xample*\t\x08\xe8\x07\x10\x80\x80\x80\x80\x02\x42\x0b\n\tless_thanB\x0e\n\x0cgreater_than\"\xf0\x14\n\x0bUInt64Rules\x12\x85\x01\n\x05\x63onst\x18\x01 \x01(\x04\x42o\xc2Hl\nj\n\x0cuint64.const\x1aZthis != getField(rules, \'const\') ? \'must equal %s\'.format([getField(rules, \'const\')]) : \'\'R\x05\x63onst\x12\x89\x01\n\x02lt\x18\x02 \x01(\x04\x42w\xc2Ht\nr\n\tuint64.lt\x1a\x65!has(rules.gte) && !has(rules.gt) && this >= rules.lt? \'must be less than %s\'.format([rules.lt]) : \'\'H\x00R\x02lt\x12\x9c\x01\n\x03lte\x18\x03 \x01(\x04\x42\x87\x01\xc2H\x83\x01\n\x80\x01\n\nuint64.lte\x1ar!has(rules.gte) && !has(rules.gt) && this > rules.lte? \'must be less than or equal to %s\'.format([rules.lte]) : \'\'H\x00R\x03lte\x12\x82\x07\n\x02gt\x18\x04 \x01(\x04\x42\xef\x06\xc2H\xeb\x06\nu\n\tuint64.gt\x1ah!has(rules.lt) && !has(rules.lte) && this <= rules.gt? \'must be greater than %s\'.format([rules.gt]) : \'\'\n\xae\x01\n\x0cuint64.gt_lt\x1a\x9d\x01has(rules.lt) && rules.lt >= rules.gt && (this >= rules.lt || this <= rules.gt)? \'must be greater than %s and less than %s\'.format([rules.gt, rules.lt]) : \'\'\n\xb6\x01\n\x16uint64.gt_lt_exclusive\x1a\x9b\x01has(rules.lt) && rules.lt < rules.gt && (rules.lt <= this && this <= rules.gt)? \'must be greater than %s or less than %s\'.format([rules.gt, rules.lt]) : \'\'\n\xbe\x01\n\ruint64.gt_lte\x1a\xac\x01has(rules.lte) && rules.lte >= rules.gt && (this > rules.lte || this <= rules.gt)? \'must be greater than %s and less than or equal to %s\'.format([rules.gt, rules.lte]) : \'\'\n\xc6\x01\n\x17uint64.gt_lte_exclusive\x1a\xaa\x01has(rules.lte) && rules.lte < rules.gt && (rules.lte < this && this <= rules.gt)? \'must be greater than %s or less than or equal to %s\'.format([rules.gt, rules.lte]) : \'\'H\x01R\x02gt\x12\xcf\x07\n\x03gte\x18\x05 \x01(\x04\x42\xba\x07\xc2H\xb6\x07\n\x83\x01\n\nuint64.gte\x1au!has(rules.lt) && !has(rules.lte) && this < rules.gte? \'must be greater than or equal to %s\'.format([rules.gte]) : \'\'\n\xbd\x01\n\ruint64.gte_lt\x1a\xab\x01has(rules.lt) && rules.lt >= rules.gte && (this >= rules.lt || this < rules.gte)? \'must be greater than or equal to %s and less than %s\'.format([rules.gte, rules.lt]) : \'\'\n\xc5\x01\n\x17uint64.gte_lt_exclusive\x1a\xa9\x01has(rules.lt) && rules.lt < rules.gte && (rules.lt <= this && this < rules.gte)? \'must be greater than or equal to %s or less than %s\'.format([rules.gte, rules.lt]) : \'\'\n\xcd\x01\n\x0euint64.gte_lte\x1a\xba\x01has(rules.lte) && rules.lte >= rules.gte && (this > rules.lte || this < rules.gte)? \'must be greater than or equal to %s and less than or equal to %s\'.format([rules.gte, rules.lte]) : \'\'\n\xd5\x01\n\x18uint64.gte_lte_exclusive\x1a\xb8\x01has(rules.lte) && rules.lte < rules.gte && (rules.lte < this && this < rules.gte)? \'must be greater than or equal to %s or less than or equal to %s\'.format([rules.gte, rules.lte]) : \'\'H\x01R\x03gte\x12~\n\x02in\x18\x06 \x03(\x04\x42n\xc2Hk\ni\n\tuint64.in\x1a\\!(this in getField(rules, \'in\')) ? \'must be in list %s\'.format([getField(rules, \'in\')]) : \'\'R\x02in\x12x\n\x06not_in\x18\x07 \x03(\x04\x42\x61\xc2H^\n\\\n\ruint64.not_in\x1aKthis in rules.not_in ? \'must not be in list %s\'.format([rules.not_in]) : \'\'R\x05notIn\x12\x35\n\x07\x65xample\x18\x08 \x03(\x04\x42\x1b\xc2H\x18\n\x16\n\x0euint64.example\x1a\x04trueR\x07\x65xample*\t\x08\xe8\x07\x10\x80\x80\x80\x80\x02\x42\x0b\n\tless_thanB\x0e\n\x0cgreater_than\"\xf0\x14\n\x0bSInt32Rules\x12\x85\x01\n\x05\x63onst\x18\x01 \x01(\x11\x42o\xc2Hl\nj\n\x0csint32.const\x1aZthis != getField(rules, \'const\') ? \'must equal %s\'.format([getField(rules, \'const\')]) : \'\'R\x05\x63onst\x12\x89\x01\n\x02lt\x18\x02 \x01(\x11\x42w\xc2Ht\nr\n\tsint32.lt\x1a\x65!has(rules.gte) && !has(rules.gt) && this >= rules.lt? \'must be less than %s\'.format([rules.lt]) : \'\'H\x00R\x02lt\x12\x9c\x01\n\x03lte\x18\x03 \x01(\x11\x42\x87\x01\xc2H\x83\x01\n\x80\x01\n\nsint32.lte\x1ar!has(rules.gte) && !has(rules.gt) && this > rules.lte? \'must be less than or equal to %s\'.format([rules.lte]) : \'\'H\x00R\x03lte\x12\x82\x07\n\x02gt\x18\x04 \x01(\x11\x42\xef\x06\xc2H\xeb\x06\nu\n\tsint32.gt\x1ah!has(rules.lt) && !has(rules.lte) && this <= rules.gt? \'must be greater than %s\'.format([rules.gt]) : \'\'\n\xae\x01\n\x0csint32.gt_lt\x1a\x9d\x01has(rules.lt) && rules.lt >= rules.gt && (this >= rules.lt || this <= rules.gt)? \'must be greater than %s and less than %s\'.format([rules.gt, rules.lt]) : \'\'\n\xb6\x01\n\x16sint32.gt_lt_exclusive\x1a\x9b\x01has(rules.lt) && rules.lt < rules.gt && (rules.lt <= this && this <= rules.gt)? \'must be greater than %s or less than %s\'.format([rules.gt, rules.lt]) : \'\'\n\xbe\x01\n\rsint32.gt_lte\x1a\xac\x01has(rules.lte) && rules.lte >= rules.gt && (this > rules.lte || this <= rules.gt)? \'must be greater than %s and less than or equal to %s\'.format([rules.gt, rules.lte]) : \'\'\n\xc6\x01\n\x17sint32.gt_lte_exclusive\x1a\xaa\x01has(rules.lte) && rules.lte < rules.gt && (rules.lte < this && this <= rules.gt)? \'must be greater than %s or less than or equal to %s\'.format([rules.gt, rules.lte]) : \'\'H\x01R\x02gt\x12\xcf\x07\n\x03gte\x18\x05 \x01(\x11\x42\xba\x07\xc2H\xb6\x07\n\x83\x01\n\nsint32.gte\x1au!has(rules.lt) && !has(rules.lte) && this < rules.gte? \'must be greater than or equal to %s\'.format([rules.gte]) : \'\'\n\xbd\x01\n\rsint32.gte_lt\x1a\xab\x01has(rules.lt) && rules.lt >= rules.gte && (this >= rules.lt || this < rules.gte)? \'must be greater than or equal to %s and less than %s\'.format([rules.gte, rules.lt]) : \'\'\n\xc5\x01\n\x17sint32.gte_lt_exclusive\x1a\xa9\x01has(rules.lt) && rules.lt < rules.gte && (rules.lt <= this && this < rules.gte)? \'must be greater than or equal to %s or less than %s\'.format([rules.gte, rules.lt]) : \'\'\n\xcd\x01\n\x0esint32.gte_lte\x1a\xba\x01has(rules.lte) && rules.lte >= rules.gte && (this > rules.lte || this < rules.gte)? \'must be greater than or equal to %s and less than or equal to %s\'.format([rules.gte, rules.lte]) : \'\'\n\xd5\x01\n\x18sint32.gte_lte_exclusive\x1a\xb8\x01has(rules.lte) && rules.lte < rules.gte && (rules.lte < this && this < rules.gte)? \'must be greater than or equal to %s or less than or equal to %s\'.format([rules.gte, rules.lte]) : \'\'H\x01R\x03gte\x12~\n\x02in\x18\x06 \x03(\x11\x42n\xc2Hk\ni\n\tsint32.in\x1a\\!(this in getField(rules, \'in\')) ? \'must be in list %s\'.format([getField(rules, \'in\')]) : \'\'R\x02in\x12x\n\x06not_in\x18\x07 \x03(\x11\x42\x61\xc2H^\n\\\n\rsint32.not_in\x1aKthis in rules.not_in ? \'must not be in list %s\'.format([rules.not_in]) : \'\'R\x05notIn\x12\x35\n\x07\x65xample\x18\x08 \x03(\x11\x42\x1b\xc2H\x18\n\x16\n\x0esint32.example\x1a\x04trueR\x07\x65xample*\t\x08\xe8\x07\x10\x80\x80\x80\x80\x02\x42\x0b\n\tless_thanB\x0e\n\x0cgreater_than\"\xf0\x14\n\x0bSInt64Rules\x12\x85\x01\n\x05\x63onst\x18\x01 \x01(\x12\x42o\xc2Hl\nj\n\x0csint64.const\x1aZthis != getField(rules, \'const\') ? \'must equal %s\'.format([getField(rules, \'const\')]) : \'\'R\x05\x63onst\x12\x89\x01\n\x02lt\x18\x02 \x01(\x12\x42w\xc2Ht\nr\n\tsint64.lt\x1a\x65!has(rules.gte) && !has(rules.gt) && this >= rules.lt? \'must be less than %s\'.format([rules.lt]) : \'\'H\x00R\x02lt\x12\x9c\x01\n\x03lte\x18\x03 \x01(\x12\x42\x87\x01\xc2H\x83\x01\n\x80\x01\n\nsint64.lte\x1ar!has(rules.gte) && !has(rules.gt) && this > rules.lte? \'must be less than or equal to %s\'.format([rules.lte]) : \'\'H\x00R\x03lte\x12\x82\x07\n\x02gt\x18\x04 \x01(\x12\x42\xef\x06\xc2H\xeb\x06\nu\n\tsint64.gt\x1ah!has(rules.lt) && !has(rules.lte) && this <= rules.gt? \'must be greater than %s\'.format([rules.gt]) : \'\'\n\xae\x01\n\x0csint64.gt_lt\x1a\x9d\x01has(rules.lt) && rules.lt >= rules.gt && (this >= rules.lt || this <= rules.gt)? \'must be greater than %s and less than %s\'.format([rules.gt, rules.lt]) : \'\'\n\xb6\x01\n\x16sint64.gt_lt_exclusive\x1a\x9b\x01has(rules.lt) && rules.lt < rules.gt && (rules.lt <= this && this <= rules.gt)? \'must be greater than %s or less than %s\'.format([rules.gt, rules.lt]) : \'\'\n\xbe\x01\n\rsint64.gt_lte\x1a\xac\x01has(rules.lte) && rules.lte >= rules.gt && (this > rules.lte || this <= rules.gt)? \'must be greater than %s and less than or equal to %s\'.format([rules.gt, rules.lte]) : \'\'\n\xc6\x01\n\x17sint64.gt_lte_exclusive\x1a\xaa\x01has(rules.lte) && rules.lte < rules.gt && (rules.lte < this && this <= rules.gt)? \'must be greater than %s or less than or equal to %s\'.format([rules.gt, rules.lte]) : \'\'H\x01R\x02gt\x12\xcf\x07\n\x03gte\x18\x05 \x01(\x12\x42\xba\x07\xc2H\xb6\x07\n\x83\x01\n\nsint64.gte\x1au!has(rules.lt) && !has(rules.lte) && this < rules.gte? \'must be greater than or equal to %s\'.format([rules.gte]) : \'\'\n\xbd\x01\n\rsint64.gte_lt\x1a\xab\x01has(rules.lt) && rules.lt >= rules.gte && (this >= rules.lt || this < rules.gte)? \'must be greater than or equal to %s and less than %s\'.format([rules.gte, rules.lt]) : \'\'\n\xc5\x01\n\x17sint64.gte_lt_exclusive\x1a\xa9\x01has(rules.lt) && rules.lt < rules.gte && (rules.lt <= this && this < rules.gte)? \'must be greater than or equal to %s or less than %s\'.format([rules.gte, rules.lt]) : \'\'\n\xcd\x01\n\x0esint64.gte_lte\x1a\xba\x01has(rules.lte) && rules.lte >= rules.gte && (this > rules.lte || this < rules.gte)? \'must be greater than or equal to %s and less than or equal to %s\'.format([rules.gte, rules.lte]) : \'\'\n\xd5\x01\n\x18sint64.gte_lte_exclusive\x1a\xb8\x01has(rules.lte) && rules.lte < rules.gte && (rules.lte < this && this < rules.gte)? \'must be greater than or equal to %s or less than or equal to %s\'.format([rules.gte, rules.lte]) : \'\'H\x01R\x03gte\x12~\n\x02in\x18\x06 \x03(\x12\x42n\xc2Hk\ni\n\tsint64.in\x1a\\!(this in getField(rules, \'in\')) ? \'must be in list %s\'.format([getField(rules, \'in\')]) : \'\'R\x02in\x12x\n\x06not_in\x18\x07 \x03(\x12\x42\x61\xc2H^\n\\\n\rsint64.not_in\x1aKthis in rules.not_in ? \'must not be in list %s\'.format([rules.not_in]) : \'\'R\x05notIn\x12\x35\n\x07\x65xample\x18\x08 \x03(\x12\x42\x1b\xc2H\x18\n\x16\n\x0esint64.example\x1a\x04trueR\x07\x65xample*\t\x08\xe8\x07\x10\x80\x80\x80\x80\x02\x42\x0b\n\tless_thanB\x0e\n\x0cgreater_than\"\x81\x15\n\x0c\x46ixed32Rules\x12\x86\x01\n\x05\x63onst\x18\x01 \x01(\x07\x42p\xc2Hm\nk\n\rfixed32.const\x1aZthis != getField(rules, \'const\') ? \'must equal %s\'.format([getField(rules, \'const\')]) : \'\'R\x05\x63onst\x12\x8a\x01\n\x02lt\x18\x02 \x01(\x07\x42x\xc2Hu\ns\n\nfixed32.lt\x1a\x65!has(rules.gte) && !has(rules.gt) && this >= rules.lt? \'must be less than %s\'.format([rules.lt]) : \'\'H\x00R\x02lt\x12\x9d\x01\n\x03lte\x18\x03 \x01(\x07\x42\x88\x01\xc2H\x84\x01\n\x81\x01\n\x0b\x66ixed32.lte\x1ar!has(rules.gte) && !has(rules.gt) && this > rules.lte? \'must be less than or equal to %s\'.format([rules.lte]) : \'\'H\x00R\x03lte\x12\x87\x07\n\x02gt\x18\x04 \x01(\x07\x42\xf4\x06\xc2H\xf0\x06\nv\n\nfixed32.gt\x1ah!has(rules.lt) && !has(rules.lte) && this <= rules.gt? \'must be greater than %s\'.format([rules.gt]) : \'\'\n\xaf\x01\n\rfixed32.gt_lt\x1a\x9d\x01has(rules.lt) && rules.lt >= rules.gt && (this >= rules.lt || this <= rules.gt)? \'must be greater than %s and less than %s\'.format([rules.gt, rules.lt]) : \'\'\n\xb7\x01\n\x17\x66ixed32.gt_lt_exclusive\x1a\x9b\x01has(rules.lt) && rules.lt < rules.gt && (rules.lt <= this && this <= rules.gt)? \'must be greater than %s or less than %s\'.format([rules.gt, rules.lt]) : \'\'\n\xbf\x01\n\x0e\x66ixed32.gt_lte\x1a\xac\x01has(rules.lte) && rules.lte >= rules.gt && (this > rules.lte || this <= rules.gt)? \'must be greater than %s and less than or equal to %s\'.format([rules.gt, rules.lte]) : \'\'\n\xc7\x01\n\x18\x66ixed32.gt_lte_exclusive\x1a\xaa\x01has(rules.lte) && rules.lte < rules.gt && (rules.lte < this && this <= rules.gt)? \'must be greater than %s or less than or equal to %s\'.format([rules.gt, rules.lte]) : \'\'H\x01R\x02gt\x12\xd4\x07\n\x03gte\x18\x05 \x01(\x07\x42\xbf\x07\xc2H\xbb\x07\n\x84\x01\n\x0b\x66ixed32.gte\x1au!has(rules.lt) && !has(rules.lte) && this < rules.gte? \'must be greater than or equal to %s\'.format([rules.gte]) : \'\'\n\xbe\x01\n\x0e\x66ixed32.gte_lt\x1a\xab\x01has(rules.lt) && rules.lt >= rules.gte && (this >= rules.lt || this < rules.gte)? \'must be greater than or equal to %s and less than %s\'.format([rules.gte, rules.lt]) : \'\'\n\xc6\x01\n\x18\x66ixed32.gte_lt_exclusive\x1a\xa9\x01has(rules.lt) && rules.lt < rules.gte && (rules.lt <= this && this < rules.gte)? \'must be greater than or equal to %s or less than %s\'.format([rules.gte, rules.lt]) : \'\'\n\xce\x01\n\x0f\x66ixed32.gte_lte\x1a\xba\x01has(rules.lte) && rules.lte >= rules.gte && (this > rules.lte || this < rules.gte)? \'must be greater than or equal to %s and less than or equal to %s\'.format([rules.gte, rules.lte]) : \'\'\n\xd6\x01\n\x19\x66ixed32.gte_lte_exclusive\x1a\xb8\x01has(rules.lte) && rules.lte < rules.gte && (rules.lte < this && this < rules.gte)? \'must be greater than or equal to %s or less than or equal to %s\'.format([rules.gte, rules.lte]) : \'\'H\x01R\x03gte\x12\x7f\n\x02in\x18\x06 \x03(\x07\x42o\xc2Hl\nj\n\nfixed32.in\x1a\\!(this in getField(rules, \'in\')) ? \'must be in list %s\'.format([getField(rules, \'in\')]) : \'\'R\x02in\x12y\n\x06not_in\x18\x07 \x03(\x07\x42\x62\xc2H_\n]\n\x0e\x66ixed32.not_in\x1aKthis in rules.not_in ? \'must not be in list %s\'.format([rules.not_in]) : \'\'R\x05notIn\x12\x36\n\x07\x65xample\x18\x08 \x03(\x07\x42\x1c\xc2H\x19\n\x17\n\x0f\x66ixed32.example\x1a\x04trueR\x07\x65xample*\t\x08\xe8\x07\x10\x80\x80\x80\x80\x02\x42\x0b\n\tless_thanB\x0e\n\x0cgreater_than\"\x81\x15\n\x0c\x46ixed64Rules\x12\x86\x01\n\x05\x63onst\x18\x01 \x01(\x06\x42p\xc2Hm\nk\n\rfixed64.const\x1aZthis != getField(rules, \'const\') ? \'must equal %s\'.format([getField(rules, \'const\')]) : \'\'R\x05\x63onst\x12\x8a\x01\n\x02lt\x18\x02 \x01(\x06\x42x\xc2Hu\ns\n\nfixed64.lt\x1a\x65!has(rules.gte) && !has(rules.gt) && this >= rules.lt? \'must be less than %s\'.format([rules.lt]) : \'\'H\x00R\x02lt\x12\x9d\x01\n\x03lte\x18\x03 \x01(\x06\x42\x88\x01\xc2H\x84\x01\n\x81\x01\n\x0b\x66ixed64.lte\x1ar!has(rules.gte) && !has(rules.gt) && this > rules.lte? \'must be less than or equal to %s\'.format([rules.lte]) : \'\'H\x00R\x03lte\x12\x87\x07\n\x02gt\x18\x04 \x01(\x06\x42\xf4\x06\xc2H\xf0\x06\nv\n\nfixed64.gt\x1ah!has(rules.lt) && !has(rules.lte) && this <= rules.gt? \'must be greater than %s\'.format([rules.gt]) : \'\'\n\xaf\x01\n\rfixed64.gt_lt\x1a\x9d\x01has(rules.lt) && rules.lt >= rules.gt && (this >= rules.lt || this <= rules.gt)? \'must be greater than %s and less than %s\'.format([rules.gt, rules.lt]) : \'\'\n\xb7\x01\n\x17\x66ixed64.gt_lt_exclusive\x1a\x9b\x01has(rules.lt) && rules.lt < rules.gt && (rules.lt <= this && this <= rules.gt)? \'must be greater than %s or less than %s\'.format([rules.gt, rules.lt]) : \'\'\n\xbf\x01\n\x0e\x66ixed64.gt_lte\x1a\xac\x01has(rules.lte) && rules.lte >= rules.gt && (this > rules.lte || this <= rules.gt)? \'must be greater than %s and less than or equal to %s\'.format([rules.gt, rules.lte]) : \'\'\n\xc7\x01\n\x18\x66ixed64.gt_lte_exclusive\x1a\xaa\x01has(rules.lte) && rules.lte < rules.gt && (rules.lte < this && this <= rules.gt)? \'must be greater than %s or less than or equal to %s\'.format([rules.gt, rules.lte]) : \'\'H\x01R\x02gt\x12\xd4\x07\n\x03gte\x18\x05 \x01(\x06\x42\xbf\x07\xc2H\xbb\x07\n\x84\x01\n\x0b\x66ixed64.gte\x1au!has(rules.lt) && !has(rules.lte) && this < rules.gte? \'must be greater than or equal to %s\'.format([rules.gte]) : \'\'\n\xbe\x01\n\x0e\x66ixed64.gte_lt\x1a\xab\x01has(rules.lt) && rules.lt >= rules.gte && (this >= rules.lt || this < rules.gte)? \'must be greater than or equal to %s and less than %s\'.format([rules.gte, rules.lt]) : \'\'\n\xc6\x01\n\x18\x66ixed64.gte_lt_exclusive\x1a\xa9\x01has(rules.lt) && rules.lt < rules.gte && (rules.lt <= this && this < rules.gte)? \'must be greater than or equal to %s or less than %s\'.format([rules.gte, rules.lt]) : \'\'\n\xce\x01\n\x0f\x66ixed64.gte_lte\x1a\xba\x01has(rules.lte) && rules.lte >= rules.gte && (this > rules.lte || this < rules.gte)? \'must be greater than or equal to %s and less than or equal to %s\'.format([rules.gte, rules.lte]) : \'\'\n\xd6\x01\n\x19\x66ixed64.gte_lte_exclusive\x1a\xb8\x01has(rules.lte) && rules.lte < rules.gte && (rules.lte < this && this < rules.gte)? \'must be greater than or equal to %s or less than or equal to %s\'.format([rules.gte, rules.lte]) : \'\'H\x01R\x03gte\x12\x7f\n\x02in\x18\x06 \x03(\x06\x42o\xc2Hl\nj\n\nfixed64.in\x1a\\!(this in getField(rules, \'in\')) ? \'must be in list %s\'.format([getField(rules, \'in\')]) : \'\'R\x02in\x12y\n\x06not_in\x18\x07 \x03(\x06\x42\x62\xc2H_\n]\n\x0e\x66ixed64.not_in\x1aKthis in rules.not_in ? \'must not be in list %s\'.format([rules.not_in]) : \'\'R\x05notIn\x12\x36\n\x07\x65xample\x18\x08 \x03(\x06\x42\x1c\xc2H\x19\n\x17\n\x0f\x66ixed64.example\x1a\x04trueR\x07\x65xample*\t\x08\xe8\x07\x10\x80\x80\x80\x80\x02\x42\x0b\n\tless_thanB\x0e\n\x0cgreater_than\"\x93\x15\n\rSFixed32Rules\x12\x87\x01\n\x05\x63onst\x18\x01 \x01(\x0f\x42q\xc2Hn\nl\n\x0esfixed32.const\x1aZthis != getField(rules, \'const\') ? \'must equal %s\'.format([getField(rules, \'const\')]) : \'\'R\x05\x63onst\x12\x8b\x01\n\x02lt\x18\x02 \x01(\x0f\x42y\xc2Hv\nt\n\x0bsfixed32.lt\x1a\x65!has(rules.gte) && !has(rules.gt) && this >= rules.lt? \'must be less than %s\'.format([rules.lt]) : \'\'H\x00R\x02lt\x12\x9e\x01\n\x03lte\x18\x03 \x01(\x0f\x42\x89\x01\xc2H\x85\x01\n\x82\x01\n\x0csfixed32.lte\x1ar!has(rules.gte) && !has(rules.gt) && this > rules.lte? \'must be less than or equal to %s\'.format([rules.lte]) : \'\'H\x00R\x03lte\x12\x8c\x07\n\x02gt\x18\x04 \x01(\x0f\x42\xf9\x06\xc2H\xf5\x06\nw\n\x0bsfixed32.gt\x1ah!has(rules.lt) && !has(rules.lte) && this <= rules.gt? \'must be greater than %s\'.format([rules.gt]) : \'\'\n\xb0\x01\n\x0esfixed32.gt_lt\x1a\x9d\x01has(rules.lt) && rules.lt >= rules.gt && (this >= rules.lt || this <= rules.gt)? \'must be greater than %s and less than %s\'.format([rules.gt, rules.lt]) : \'\'\n\xb8\x01\n\x18sfixed32.gt_lt_exclusive\x1a\x9b\x01has(rules.lt) && rules.lt < rules.gt && (rules.lt <= this && this <= rules.gt)? \'must be greater than %s or less than %s\'.format([rules.gt, rules.lt]) : \'\'\n\xc0\x01\n\x0fsfixed32.gt_lte\x1a\xac\x01has(rules.lte) && rules.lte >= rules.gt && (this > rules.lte || this <= rules.gt)? \'must be greater than %s and less than or equal to %s\'.format([rules.gt, rules.lte]) : \'\'\n\xc8\x01\n\x19sfixed32.gt_lte_exclusive\x1a\xaa\x01has(rules.lte) && rules.lte < rules.gt && (rules.lte < this && this <= rules.gt)? \'must be greater than %s or less than or equal to %s\'.format([rules.gt, rules.lte]) : \'\'H\x01R\x02gt\x12\xd9\x07\n\x03gte\x18\x05 \x01(\x0f\x42\xc4\x07\xc2H\xc0\x07\n\x85\x01\n\x0csfixed32.gte\x1au!has(rules.lt) && !has(rules.lte) && this < rules.gte? \'must be greater than or equal to %s\'.format([rules.gte]) : \'\'\n\xbf\x01\n\x0fsfixed32.gte_lt\x1a\xab\x01has(rules.lt) && rules.lt >= rules.gte && (this >= rules.lt || this < rules.gte)? \'must be greater than or equal to %s and less than %s\'.format([rules.gte, rules.lt]) : \'\'\n\xc7\x01\n\x19sfixed32.gte_lt_exclusive\x1a\xa9\x01has(rules.lt) && rules.lt < rules.gte && (rules.lt <= this && this < rules.gte)? \'must be greater than or equal to %s or less than %s\'.format([rules.gte, rules.lt]) : \'\'\n\xcf\x01\n\x10sfixed32.gte_lte\x1a\xba\x01has(rules.lte) && rules.lte >= rules.gte && (this > rules.lte || this < rules.gte)? \'must be greater than or equal to %s and less than or equal to %s\'.format([rules.gte, rules.lte]) : \'\'\n\xd7\x01\n\x1asfixed32.gte_lte_exclusive\x1a\xb8\x01has(rules.lte) && rules.lte < rules.gte && (rules.lte < this && this < rules.gte)? \'must be greater than or equal to %s or less than or equal to %s\'.format([rules.gte, rules.lte]) : \'\'H\x01R\x03gte\x12\x80\x01\n\x02in\x18\x06 \x03(\x0f\x42p\xc2Hm\nk\n\x0bsfixed32.in\x1a\\!(this in getField(rules, \'in\')) ? \'must be in list %s\'.format([getField(rules, \'in\')]) : \'\'R\x02in\x12z\n\x06not_in\x18\x07 \x03(\x0f\x42\x63\xc2H`\n^\n\x0fsfixed32.not_in\x1aKthis in rules.not_in ? \'must not be in list %s\'.format([rules.not_in]) : \'\'R\x05notIn\x12\x37\n\x07\x65xample\x18\x08 \x03(\x0f\x42\x1d\xc2H\x1a\n\x18\n\x10sfixed32.example\x1a\x04trueR\x07\x65xample*\t\x08\xe8\x07\x10\x80\x80\x80\x80\x02\x42\x0b\n\tless_thanB\x0e\n\x0cgreater_than\"\x93\x15\n\rSFixed64Rules\x12\x87\x01\n\x05\x63onst\x18\x01 \x01(\x10\x42q\xc2Hn\nl\n\x0esfixed64.const\x1aZthis != getField(rules, \'const\') ? \'must equal %s\'.format([getField(rules, \'const\')]) : \'\'R\x05\x63onst\x12\x8b\x01\n\x02lt\x18\x02 \x01(\x10\x42y\xc2Hv\nt\n\x0bsfixed64.lt\x1a\x65!has(rules.gte) && !has(rules.gt) && this >= rules.lt? \'must be less than %s\'.format([rules.lt]) : \'\'H\x00R\x02lt\x12\x9e\x01\n\x03lte\x18\x03 \x01(\x10\x42\x89\x01\xc2H\x85\x01\n\x82\x01\n\x0csfixed64.lte\x1ar!has(rules.gte) && !has(rules.gt) && this > rules.lte? \'must be less than or equal to %s\'.format([rules.lte]) : \'\'H\x00R\x03lte\x12\x8c\x07\n\x02gt\x18\x04 \x01(\x10\x42\xf9\x06\xc2H\xf5\x06\nw\n\x0bsfixed64.gt\x1ah!has(rules.lt) && !has(rules.lte) && this <= rules.gt? \'must be greater than %s\'.format([rules.gt]) : \'\'\n\xb0\x01\n\x0esfixed64.gt_lt\x1a\x9d\x01has(rules.lt) && rules.lt >= rules.gt && (this >= rules.lt || this <= rules.gt)? \'must be greater than %s and less than %s\'.format([rules.gt, rules.lt]) : \'\'\n\xb8\x01\n\x18sfixed64.gt_lt_exclusive\x1a\x9b\x01has(rules.lt) && rules.lt < rules.gt && (rules.lt <= this && this <= rules.gt)? \'must be greater than %s or less than %s\'.format([rules.gt, rules.lt]) : \'\'\n\xc0\x01\n\x0fsfixed64.gt_lte\x1a\xac\x01has(rules.lte) && rules.lte >= rules.gt && (this > rules.lte || this <= rules.gt)? \'must be greater than %s and less than or equal to %s\'.format([rules.gt, rules.lte]) : \'\'\n\xc8\x01\n\x19sfixed64.gt_lte_exclusive\x1a\xaa\x01has(rules.lte) && rules.lte < rules.gt && (rules.lte < this && this <= rules.gt)? \'must be greater than %s or less than or equal to %s\'.format([rules.gt, rules.lte]) : \'\'H\x01R\x02gt\x12\xd9\x07\n\x03gte\x18\x05 \x01(\x10\x42\xc4\x07\xc2H\xc0\x07\n\x85\x01\n\x0csfixed64.gte\x1au!has(rules.lt) && !has(rules.lte) && this < rules.gte? \'must be greater than or equal to %s\'.format([rules.gte]) : \'\'\n\xbf\x01\n\x0fsfixed64.gte_lt\x1a\xab\x01has(rules.lt) && rules.lt >= rules.gte && (this >= rules.lt || this < rules.gte)? \'must be greater than or equal to %s and less than %s\'.format([rules.gte, rules.lt]) : \'\'\n\xc7\x01\n\x19sfixed64.gte_lt_exclusive\x1a\xa9\x01has(rules.lt) && rules.lt < rules.gte && (rules.lt <= this && this < rules.gte)? \'must be greater than or equal to %s or less than %s\'.format([rules.gte, rules.lt]) : \'\'\n\xcf\x01\n\x10sfixed64.gte_lte\x1a\xba\x01has(rules.lte) && rules.lte >= rules.gte && (this > rules.lte || this < rules.gte)? \'must be greater than or equal to %s and less than or equal to %s\'.format([rules.gte, rules.lte]) : \'\'\n\xd7\x01\n\x1asfixed64.gte_lte_exclusive\x1a\xb8\x01has(rules.lte) && rules.lte < rules.gte && (rules.lte < this && this < rules.gte)? \'must be greater than or equal to %s or less than or equal to %s\'.format([rules.gte, rules.lte]) : \'\'H\x01R\x03gte\x12\x80\x01\n\x02in\x18\x06 \x03(\x10\x42p\xc2Hm\nk\n\x0bsfixed64.in\x1a\\!(this in getField(rules, \'in\')) ? \'must be in list %s\'.format([getField(rules, \'in\')]) : \'\'R\x02in\x12z\n\x06not_in\x18\x07 \x03(\x10\x42\x63\xc2H`\n^\n\x0fsfixed64.not_in\x1aKthis in rules.not_in ? \'must not be in list %s\'.format([rules.not_in]) : \'\'R\x05notIn\x12\x37\n\x07\x65xample\x18\x08 \x03(\x10\x42\x1d\xc2H\x1a\n\x18\n\x10sfixed64.example\x1a\x04trueR\x07\x65xample*\t\x08\xe8\x07\x10\x80\x80\x80\x80\x02\x42\x0b\n\tless_thanB\x0e\n\x0cgreater_than\"\xd1\x01\n\tBoolRules\x12\x83\x01\n\x05\x63onst\x18\x01 \x01(\x08\x42m\xc2Hj\nh\n\nbool.const\x1aZthis != getField(rules, \'const\') ? \'must equal %s\'.format([getField(rules, \'const\')]) : \'\'R\x05\x63onst\x12\x33\n\x07\x65xample\x18\x02 \x03(\x08\x42\x19\xc2H\x16\n\x14\n\x0c\x62ool.example\x1a\x04trueR\x07\x65xample*\t\x08\xe8\x07\x10\x80\x80\x80\x80\x02\"\xcf?\n\x0bStringRules\x12\x87\x01\n\x05\x63onst\x18\x01 \x01(\tBq\xc2Hn\nl\n\x0cstring.const\x1a\\this != getField(rules, \'const\') ? \'must equal `%s`\'.format([getField(rules, \'const\')]) : \'\'R\x05\x63onst\x12v\n\x03len\x18\x13 \x01(\x04\x42\x64\xc2Ha\n_\n\nstring.len\x1aQuint(this.size()) != rules.len ? \'must be %s characters\'.format([rules.len]) : \'\'R\x03len\x12\x91\x01\n\x07min_len\x18\x02 \x01(\x04\x42x\xc2Hu\ns\n\x0estring.min_len\x1a\x61uint(this.size()) < rules.min_len ? \'must be at least %s characters\'.format([rules.min_len]) : \'\'R\x06minLen\x12\x90\x01\n\x07max_len\x18\x03 \x01(\x04\x42w\xc2Ht\nr\n\x0estring.max_len\x1a`uint(this.size()) > rules.max_len ? \'must be at most %s characters\'.format([rules.max_len]) : \'\'R\x06maxLen\x12\x95\x01\n\tlen_bytes\x18\x14 \x01(\x04\x42x\xc2Hu\ns\n\x10string.len_bytes\x1a_uint(bytes(this).size()) != rules.len_bytes ? \'must be %s bytes\'.format([rules.len_bytes]) : \'\'R\x08lenBytes\x12\x9e\x01\n\tmin_bytes\x18\x04 \x01(\x04\x42\x80\x01\xc2H}\n{\n\x10string.min_bytes\x1aguint(bytes(this).size()) < rules.min_bytes ? \'must be at least %s bytes\'.format([rules.min_bytes]) : \'\'R\x08minBytes\x12\x9c\x01\n\tmax_bytes\x18\x05 \x01(\x04\x42\x7f\xc2H|\nz\n\x10string.max_bytes\x1a\x66uint(bytes(this).size()) > rules.max_bytes ? \'must be at most %s bytes\'.format([rules.max_bytes]) : \'\'R\x08maxBytes\x12\x90\x01\n\x07pattern\x18\x06 \x01(\tBv\xc2Hs\nq\n\x0estring.pattern\x1a_!this.matches(rules.pattern) ? \'does not match regex pattern `%s`\'.format([rules.pattern]) : \'\'R\x07pattern\x12\x86\x01\n\x06prefix\x18\x07 \x01(\tBn\xc2Hk\ni\n\rstring.prefix\x1aX!this.startsWith(rules.prefix) ? \'does not have prefix `%s`\'.format([rules.prefix]) : \'\'R\x06prefix\x12\x84\x01\n\x06suffix\x18\x08 \x01(\tBl\xc2Hi\ng\n\rstring.suffix\x1aV!this.endsWith(rules.suffix) ? \'does not have suffix `%s`\'.format([rules.suffix]) : \'\'R\x06suffix\x12\x94\x01\n\x08\x63ontains\x18\t \x01(\tBx\xc2Hu\ns\n\x0fstring.contains\x1a`!this.contains(rules.contains) ? \'does not contain substring `%s`\'.format([rules.contains]) : \'\'R\x08\x63ontains\x12\x9e\x01\n\x0cnot_contains\x18\x17 \x01(\tB{\xc2Hx\nv\n\x13string.not_contains\x1a_this.contains(rules.not_contains) ? \'contains substring `%s`\'.format([rules.not_contains]) : \'\'R\x0bnotContains\x12~\n\x02in\x18\n \x03(\tBn\xc2Hk\ni\n\tstring.in\x1a\\!(this in getField(rules, \'in\')) ? \'must be in list %s\'.format([getField(rules, \'in\')]) : \'\'R\x02in\x12x\n\x06not_in\x18\x0b \x03(\tBa\xc2H^\n\\\n\rstring.not_in\x1aKthis in rules.not_in ? \'must not be in list %s\'.format([rules.not_in]) : \'\'R\x05notIn\x12\xe0\x01\n\x05\x65mail\x18\x0c \x01(\x08\x42\xc7\x01\xc2H\xc3\x01\n[\n\x0cstring.email\x12\x1dmust be a valid email address\x1a,!rules.email || this == \'\' || this.isEmail()\nd\n\x12string.email_empty\x12\x32value is empty, which is not a valid email address\x1a\x1a!rules.email || this != \'\'H\x00R\x05\x65mail\x12\xeb\x01\n\x08hostname\x18\r \x01(\x08\x42\xcc\x01\xc2H\xc8\x01\n_\n\x0fstring.hostname\x12\x18must be a valid hostname\x1a\x32!rules.hostname || this == \'\' || this.isHostname()\ne\n\x15string.hostname_empty\x12-value is empty, which is not a valid hostname\x1a\x1d!rules.hostname || this != \'\'H\x00R\x08hostname\x12\xc5\x01\n\x02ip\x18\x0e \x01(\x08\x42\xb2\x01\xc2H\xae\x01\nO\n\tstring.ip\x12\x1amust be a valid IP address\x1a&!rules.ip || this == \'\' || this.isIp()\n[\n\x0fstring.ip_empty\x12/value is empty, which is not a valid IP address\x1a\x17!rules.ip || this != \'\'H\x00R\x02ip\x12\xd6\x01\n\x04ipv4\x18\x0f \x01(\x08\x42\xbf\x01\xc2H\xbb\x01\nV\n\x0bstring.ipv4\x12\x1cmust be a valid IPv4 address\x1a)!rules.ipv4 || this == \'\' || this.isIp(4)\na\n\x11string.ipv4_empty\x12\x31value is empty, which is not a valid IPv4 address\x1a\x19!rules.ipv4 || this != \'\'H\x00R\x04ipv4\x12\xd6\x01\n\x04ipv6\x18\x10 \x01(\x08\x42\xbf\x01\xc2H\xbb\x01\nV\n\x0bstring.ipv6\x12\x1cmust be a valid IPv6 address\x1a)!rules.ipv6 || this == \'\' || this.isIp(6)\na\n\x11string.ipv6_empty\x12\x31value is empty, which is not a valid IPv6 address\x1a\x19!rules.ipv6 || this != \'\'H\x00R\x04ipv6\x12\xbe\x01\n\x03uri\x18\x11 \x01(\x08\x42\xa9\x01\xc2H\xa5\x01\nK\n\nstring.uri\x12\x13must be a valid URI\x1a(!rules.uri || this == \'\' || this.isUri()\nV\n\x10string.uri_empty\x12(value is empty, which is not a valid URI\x1a\x18!rules.uri || this != \'\'H\x00R\x03uri\x12r\n\x07uri_ref\x18\x12 \x01(\x08\x42W\xc2HT\nR\n\x0estring.uri_ref\x12\x1dmust be a valid URI Reference\x1a!!rules.uri_ref || this.isUriRef()H\x00R\x06uriRef\x12\x92\x02\n\x07\x61\x64\x64ress\x18\x15 \x01(\x08\x42\xf5\x01\xc2H\xf1\x01\n{\n\x0estring.address\x12\'must be a valid hostname, or ip address\x1a@!rules.address || this == \'\' || this.isHostname() || this.isIp()\nr\n\x14string.address_empty\x12!rules.ipv4_with_prefixlen || this == \'\' || this.isIpPrefix(4)\n\x92\x01\n string.ipv4_with_prefixlen_empty\x12\x44value is empty, which is not a valid IPv4 address with prefix length\x1a(!rules.ipv4_with_prefixlen || this != \'\'H\x00R\x11ipv4WithPrefixlen\x12\xdc\x02\n\x13ipv6_with_prefixlen\x18\x1c \x01(\x08\x42\xa9\x02\xc2H\xa5\x02\n\x8d\x01\n\x1astring.ipv6_with_prefixlen\x12/must be a valid IPv6 address with prefix length\x1a>!rules.ipv6_with_prefixlen || this == \'\' || this.isIpPrefix(6)\n\x92\x01\n string.ipv6_with_prefixlen_empty\x12\x44value is empty, which is not a valid IPv6 address with prefix length\x1a(!rules.ipv6_with_prefixlen || this != \'\'H\x00R\x11ipv6WithPrefixlen\x12\xf6\x01\n\tip_prefix\x18\x1d \x01(\x08\x42\xd6\x01\xc2H\xd2\x01\nf\n\x10string.ip_prefix\x12\x19must be a valid IP prefix\x1a\x37!rules.ip_prefix || this == \'\' || this.isIpPrefix(true)\nh\n\x16string.ip_prefix_empty\x12.value is empty, which is not a valid IP prefix\x1a\x1e!rules.ip_prefix || this != \'\'H\x00R\x08ipPrefix\x12\x89\x02\n\x0bipv4_prefix\x18\x1e \x01(\x08\x42\xe5\x01\xc2H\xe1\x01\no\n\x12string.ipv4_prefix\x12\x1bmust be a valid IPv4 prefix\x1a!rules.host_and_port || this == \'\' || this.isHostAndPort(true)\ny\n\x1astring.host_and_port_empty\x12\x37value is empty, which is not a valid host and port pair\x1a\"!rules.host_and_port || this != \'\'H\x00R\x0bhostAndPort\x12\xf4\x01\n\x04ulid\x18# \x01(\x08\x42\xdd\x01\xc2H\xd9\x01\n|\n\x0bstring.ulid\x12\x14must be a valid ULID\x1aW!rules.ulid || this == \'\' || this.matches(\'^[0-7][0-9A-HJKMNP-TV-Za-hjkmnp-tv-z]{25}$\')\nY\n\x11string.ulid_empty\x12)value is empty, which is not a valid ULID\x1a\x19!rules.ulid || this != \'\'H\x00R\x04ulid\x12\xe1\x02\n\x0cprotobuf_fqn\x18% \x01(\x08\x42\xbb\x02\xc2H\xb7\x02\n\xaf\x01\n\x13string.protobuf_fqn\x12-must be a valid fully-qualified Protobuf name\x1ai!rules.protobuf_fqn || this == \'\' || this.matches(\'^[A-Za-z_][A-Za-z_0-9]*(\\\\.[A-Za-z_][A-Za-z_0-9]*)*$\')\n\x82\x01\n\x19string.protobuf_fqn_empty\x12\x42value is empty, which is not a valid fully-qualified Protobuf name\x1a!!rules.protobuf_fqn || this != \'\'H\x00R\x0bprotobufFqn\x12\xa1\x03\n\x10protobuf_dot_fqn\x18& \x01(\x08\x42\xf4\x02\xc2H\xf0\x02\n\xcd\x01\n\x17string.protobuf_dot_fqn\x12@must be a valid fully-qualified Protobuf name with a leading dot\x1ap!rules.protobuf_dot_fqn || this == \'\' || this.matches(\'^\\\\.[A-Za-z_][A-Za-z_0-9]*(\\\\.[A-Za-z_][A-Za-z_0-9]*)*$\')\n\x9d\x01\n\x1dstring.protobuf_dot_fqn_empty\x12Uvalue is empty, which is not a valid fully-qualified Protobuf name with a leading dot\x1a%!rules.protobuf_dot_fqn || this != \'\'H\x00R\x0eprotobufDotFqn\x12\xac\x05\n\x10well_known_regex\x18\x18 \x01(\x0e\x32\x18.buf.validate.KnownRegexB\xe5\x04\xc2H\xe1\x04\n\xea\x01\n#string.well_known_regex.header_name\x12 must be a valid HTTP header name\x1a\xa0\x01rules.well_known_regex != 1 || this == \'\' || this.matches(!has(rules.strict) || rules.strict ?\'^:?[0-9a-zA-Z!#$%&\\\'*+-.^_|~\\x60]+$\' :\'^[^\\u0000\\u000A\\u000D]+$\')\n\x8d\x01\n)string.well_known_regex.header_name_empty\x12\x35value is empty, which is not a valid HTTP header name\x1a)rules.well_known_regex != 1 || this != \'\'\n\xe1\x01\n$string.well_known_regex.header_value\x12!must be a valid HTTP header value\x1a\x95\x01rules.well_known_regex != 2 || this.matches(!has(rules.strict) || rules.strict ?\'^[^\\u0000-\\u0008\\u000A-\\u001F\\u007F]*$\' :\'^[^\\u0000\\u000A\\u000D]*$\')H\x00R\x0ewellKnownRegex\x12\x16\n\x06strict\x18\x19 \x01(\x08R\x06strict\x12\x35\n\x07\x65xample\x18\" \x03(\tB\x1b\xc2H\x18\n\x16\n\x0estring.example\x1a\x04trueR\x07\x65xample*\t\x08\xe8\x07\x10\x80\x80\x80\x80\x02\x42\x0c\n\nwell_known\"\xca\x12\n\nBytesRules\x12\x81\x01\n\x05\x63onst\x18\x01 \x01(\x0c\x42k\xc2Hh\nf\n\x0b\x62ytes.const\x1aWthis != getField(rules, \'const\') ? \'must be %x\'.format([getField(rules, \'const\')]) : \'\'R\x05\x63onst\x12p\n\x03len\x18\r \x01(\x04\x42^\xc2H[\nY\n\tbytes.len\x1aLuint(this.size()) != rules.len ? \'must be %s bytes\'.format([rules.len]) : \'\'R\x03len\x12\x8b\x01\n\x07min_len\x18\x02 \x01(\x04\x42r\xc2Ho\nm\n\rbytes.min_len\x1a\\uint(this.size()) < rules.min_len ? \'must be at least %s bytes\'.format([rules.min_len]) : \'\'R\x06minLen\x12\x8a\x01\n\x07max_len\x18\x03 \x01(\x04\x42q\xc2Hn\nl\n\rbytes.max_len\x1a[uint(this.size()) > rules.max_len ? \'must be at most %s bytes\'.format([rules.max_len]) : \'\'R\x06maxLen\x12\x93\x01\n\x07pattern\x18\x04 \x01(\tBy\xc2Hv\nt\n\rbytes.pattern\x1a\x63!string(this).matches(rules.pattern) ? \'must match regex pattern `%s`\'.format([rules.pattern]) : \'\'R\x07pattern\x12\x83\x01\n\x06prefix\x18\x05 \x01(\x0c\x42k\xc2Hh\nf\n\x0c\x62ytes.prefix\x1aV!this.startsWith(rules.prefix) ? \'does not have prefix %x\'.format([rules.prefix]) : \'\'R\x06prefix\x12\x81\x01\n\x06suffix\x18\x06 \x01(\x0c\x42i\xc2Hf\nd\n\x0c\x62ytes.suffix\x1aT!this.endsWith(rules.suffix) ? \'does not have suffix %x\'.format([rules.suffix]) : \'\'R\x06suffix\x12\x87\x01\n\x08\x63ontains\x18\x07 \x01(\x0c\x42k\xc2Hh\nf\n\x0e\x62ytes.contains\x1aT!this.contains(rules.contains) ? \'does not contain %x\'.format([rules.contains]) : \'\'R\x08\x63ontains\x12\xa5\x01\n\x02in\x18\x08 \x03(\x0c\x42\x94\x01\xc2H\x90\x01\n\x8d\x01\n\x08\x62ytes.in\x1a\x80\x01getField(rules, \'in\').size() > 0 && !(this in getField(rules, \'in\')) ? \'must be in list %s\'.format([getField(rules, \'in\')]) : \'\'R\x02in\x12w\n\x06not_in\x18\t \x03(\x0c\x42`\xc2H]\n[\n\x0c\x62ytes.not_in\x1aKthis in rules.not_in ? \'must not be in list %s\'.format([rules.not_in]) : \'\'R\x05notIn\x12\xe9\x01\n\x02ip\x18\n \x01(\x08\x42\xd6\x01\xc2H\xd2\x01\nn\n\x08\x62ytes.ip\x12\x1amust be a valid IP address\x1a\x46!rules.ip || this.size() == 0 || this.size() == 4 || this.size() == 16\n`\n\x0e\x62ytes.ip_empty\x12/value is empty, which is not a valid IP address\x1a\x1d!rules.ip || this.size() != 0H\x00R\x02ip\x12\xe4\x01\n\x04ipv4\x18\x0b \x01(\x08\x42\xcd\x01\xc2H\xc9\x01\n_\n\nbytes.ipv4\x12\x1cmust be a valid IPv4 address\x1a\x33!rules.ipv4 || this.size() == 0 || this.size() == 4\nf\n\x10\x62ytes.ipv4_empty\x12\x31value is empty, which is not a valid IPv4 address\x1a\x1f!rules.ipv4 || this.size() != 0H\x00R\x04ipv4\x12\xe5\x01\n\x04ipv6\x18\x0c \x01(\x08\x42\xce\x01\xc2H\xca\x01\n`\n\nbytes.ipv6\x12\x1cmust be a valid IPv6 address\x1a\x34!rules.ipv6 || this.size() == 0 || this.size() == 16\nf\n\x10\x62ytes.ipv6_empty\x12\x31value is empty, which is not a valid IPv6 address\x1a\x1f!rules.ipv6 || this.size() != 0H\x00R\x04ipv6\x12\xd5\x01\n\x04uuid\x18\x0f \x01(\x08\x42\xbe\x01\xc2H\xba\x01\nX\n\nbytes.uuid\x12\x14must be a valid UUID\x1a\x34!rules.uuid || this.size() == 0 || this.size() == 16\n^\n\x10\x62ytes.uuid_empty\x12)value is empty, which is not a valid UUID\x1a\x1f!rules.uuid || this.size() != 0H\x00R\x04uuid\x12\x34\n\x07\x65xample\x18\x0e \x03(\x0c\x42\x1a\xc2H\x17\n\x15\n\rbytes.example\x1a\x04trueR\x07\x65xample*\t\x08\xe8\x07\x10\x80\x80\x80\x80\x02\x42\x0c\n\nwell_known\"\xea\x03\n\tEnumRules\x12\x83\x01\n\x05\x63onst\x18\x01 \x01(\x05\x42m\xc2Hj\nh\n\nenum.const\x1aZthis != getField(rules, \'const\') ? \'must equal %s\'.format([getField(rules, \'const\')]) : \'\'R\x05\x63onst\x12!\n\x0c\x64\x65\x66ined_only\x18\x02 \x01(\x08R\x0b\x64\x65\x66inedOnly\x12|\n\x02in\x18\x03 \x03(\x05\x42l\xc2Hi\ng\n\x07\x65num.in\x1a\\!(this in getField(rules, \'in\')) ? \'must be in list %s\'.format([getField(rules, \'in\')]) : \'\'R\x02in\x12v\n\x06not_in\x18\x04 \x03(\x05\x42_\xc2H\\\nZ\n\x0b\x65num.not_in\x1aKthis in rules.not_in ? \'must not be in list %s\'.format([rules.not_in]) : \'\'R\x05notIn\x12\x33\n\x07\x65xample\x18\x05 \x03(\x05\x42\x19\xc2H\x16\n\x14\n\x0c\x65num.example\x1a\x04trueR\x07\x65xample*\t\x08\xe8\x07\x10\x80\x80\x80\x80\x02\"\x90\x04\n\rRepeatedRules\x12\xa0\x01\n\tmin_items\x18\x01 \x01(\x04\x42\x82\x01\xc2H\x7f\n}\n\x12repeated.min_items\x1aguint(this.size()) < rules.min_items ? \'must contain at least %d item(s)\'.format([rules.min_items]) : \'\'R\x08minItems\x12\xa6\x01\n\tmax_items\x18\x02 \x01(\x04\x42\x88\x01\xc2H\x84\x01\n\x81\x01\n\x12repeated.max_items\x1akuint(this.size()) > rules.max_items ? \'must contain no more than %s item(s)\'.format([rules.max_items]) : \'\'R\x08maxItems\x12x\n\x06unique\x18\x03 \x01(\x08\x42`\xc2H]\n[\n\x0frepeated.unique\x12(repeated value must contain unique items\x1a\x1e!rules.unique || this.unique()R\x06unique\x12.\n\x05items\x18\x04 \x01(\x0b\x32\x18.buf.validate.FieldRulesR\x05items*\t\x08\xe8\x07\x10\x80\x80\x80\x80\x02\"\xac\x03\n\x08MapRules\x12\x99\x01\n\tmin_pairs\x18\x01 \x01(\x04\x42|\xc2Hy\nw\n\rmap.min_pairs\x1a\x66uint(this.size()) < rules.min_pairs ? \'map must be at least %d entries\'.format([rules.min_pairs]) : \'\'R\x08minPairs\x12\x98\x01\n\tmax_pairs\x18\x02 \x01(\x04\x42{\xc2Hx\nv\n\rmap.max_pairs\x1a\x65uint(this.size()) > rules.max_pairs ? \'map must be at most %d entries\'.format([rules.max_pairs]) : \'\'R\x08maxPairs\x12,\n\x04keys\x18\x04 \x01(\x0b\x32\x18.buf.validate.FieldRulesR\x04keys\x12\x30\n\x06values\x18\x05 \x01(\x0b\x32\x18.buf.validate.FieldRulesR\x06values*\t\x08\xe8\x07\x10\x80\x80\x80\x80\x02\"1\n\x08\x41nyRules\x12\x0e\n\x02in\x18\x02 \x03(\tR\x02in\x12\x15\n\x06not_in\x18\x03 \x03(\tR\x05notIn\"\xec\x16\n\rDurationRules\x12\xa2\x01\n\x05\x63onst\x18\x02 \x01(\x0b\x32\x19.google.protobuf.DurationBq\xc2Hn\nl\n\x0e\x64uration.const\x1aZthis != getField(rules, \'const\') ? \'must equal %s\'.format([getField(rules, \'const\')]) : \'\'R\x05\x63onst\x12\xa6\x01\n\x02lt\x18\x03 \x01(\x0b\x32\x19.google.protobuf.DurationBy\xc2Hv\nt\n\x0b\x64uration.lt\x1a\x65!has(rules.gte) && !has(rules.gt) && this >= rules.lt? \'must be less than %s\'.format([rules.lt]) : \'\'H\x00R\x02lt\x12\xb9\x01\n\x03lte\x18\x04 \x01(\x0b\x32\x19.google.protobuf.DurationB\x89\x01\xc2H\x85\x01\n\x82\x01\n\x0c\x64uration.lte\x1ar!has(rules.gte) && !has(rules.gt) && this > rules.lte? \'must be less than or equal to %s\'.format([rules.lte]) : \'\'H\x00R\x03lte\x12\xa7\x07\n\x02gt\x18\x05 \x01(\x0b\x32\x19.google.protobuf.DurationB\xf9\x06\xc2H\xf5\x06\nw\n\x0b\x64uration.gt\x1ah!has(rules.lt) && !has(rules.lte) && this <= rules.gt? \'must be greater than %s\'.format([rules.gt]) : \'\'\n\xb0\x01\n\x0e\x64uration.gt_lt\x1a\x9d\x01has(rules.lt) && rules.lt >= rules.gt && (this >= rules.lt || this <= rules.gt)? \'must be greater than %s and less than %s\'.format([rules.gt, rules.lt]) : \'\'\n\xb8\x01\n\x18\x64uration.gt_lt_exclusive\x1a\x9b\x01has(rules.lt) && rules.lt < rules.gt && (rules.lt <= this && this <= rules.gt)? \'must be greater than %s or less than %s\'.format([rules.gt, rules.lt]) : \'\'\n\xc0\x01\n\x0f\x64uration.gt_lte\x1a\xac\x01has(rules.lte) && rules.lte >= rules.gt && (this > rules.lte || this <= rules.gt)? \'must be greater than %s and less than or equal to %s\'.format([rules.gt, rules.lte]) : \'\'\n\xc8\x01\n\x19\x64uration.gt_lte_exclusive\x1a\xaa\x01has(rules.lte) && rules.lte < rules.gt && (rules.lte < this && this <= rules.gt)? \'must be greater than %s or less than or equal to %s\'.format([rules.gt, rules.lte]) : \'\'H\x01R\x02gt\x12\xf4\x07\n\x03gte\x18\x06 \x01(\x0b\x32\x19.google.protobuf.DurationB\xc4\x07\xc2H\xc0\x07\n\x85\x01\n\x0c\x64uration.gte\x1au!has(rules.lt) && !has(rules.lte) && this < rules.gte? \'must be greater than or equal to %s\'.format([rules.gte]) : \'\'\n\xbf\x01\n\x0f\x64uration.gte_lt\x1a\xab\x01has(rules.lt) && rules.lt >= rules.gte && (this >= rules.lt || this < rules.gte)? \'must be greater than or equal to %s and less than %s\'.format([rules.gte, rules.lt]) : \'\'\n\xc7\x01\n\x19\x64uration.gte_lt_exclusive\x1a\xa9\x01has(rules.lt) && rules.lt < rules.gte && (rules.lt <= this && this < rules.gte)? \'must be greater than or equal to %s or less than %s\'.format([rules.gte, rules.lt]) : \'\'\n\xcf\x01\n\x10\x64uration.gte_lte\x1a\xba\x01has(rules.lte) && rules.lte >= rules.gte && (this > rules.lte || this < rules.gte)? \'must be greater than or equal to %s and less than or equal to %s\'.format([rules.gte, rules.lte]) : \'\'\n\xd7\x01\n\x1a\x64uration.gte_lte_exclusive\x1a\xb8\x01has(rules.lte) && rules.lte < rules.gte && (rules.lte < this && this < rules.gte)? \'must be greater than or equal to %s or less than or equal to %s\'.format([rules.gte, rules.lte]) : \'\'H\x01R\x03gte\x12\x9b\x01\n\x02in\x18\x07 \x03(\x0b\x32\x19.google.protobuf.DurationBp\xc2Hm\nk\n\x0b\x64uration.in\x1a\\!(this in getField(rules, \'in\')) ? \'must be in list %s\'.format([getField(rules, \'in\')]) : \'\'R\x02in\x12\x95\x01\n\x06not_in\x18\x08 \x03(\x0b\x32\x19.google.protobuf.DurationBc\xc2H`\n^\n\x0f\x64uration.not_in\x1aKthis in rules.not_in ? \'must not be in list %s\'.format([rules.not_in]) : \'\'R\x05notIn\x12R\n\x07\x65xample\x18\t \x03(\x0b\x32\x19.google.protobuf.DurationB\x1d\xc2H\x1a\n\x18\n\x10\x64uration.example\x1a\x04trueR\x07\x65xample*\t\x08\xe8\x07\x10\x80\x80\x80\x80\x02\x42\x0b\n\tless_thanB\x0e\n\x0cgreater_than\"\x86\x06\n\x0e\x46ieldMaskRules\x12\xc0\x01\n\x05\x63onst\x18\x01 \x01(\x0b\x32\x1a.google.protobuf.FieldMaskB\x8d\x01\xc2H\x89\x01\n\x86\x01\n\x10\x66ield_mask.const\x1arthis.paths != getField(rules, \'const\').paths ? \'must equal paths %s\'.format([getField(rules, \'const\').paths]) : \'\'R\x05\x63onst\x12\xd7\x01\n\x02in\x18\x02 \x03(\tB\xc6\x01\xc2H\xc2\x01\n\xbf\x01\n\rfield_mask.in\x1a\xad\x01!this.paths.all(p, p in getField(rules, \'in\') || getField(rules, \'in\').exists(f, p.startsWith(f+\'.\'))) ? \'must only contain paths in %s\'.format([getField(rules, \'in\')]) : \'\'R\x02in\x12\xf4\x01\n\x06not_in\x18\x03 \x03(\tB\xdc\x01\xc2H\xd8\x01\n\xd5\x01\n\x11\x66ield_mask.not_in\x1a\xbf\x01!this.paths.all(p, !(p in getField(rules, \'not_in\') || getField(rules, \'not_in\').exists(f, p.startsWith(f+\'.\')))) ? \'must not contain any paths in %s\'.format([getField(rules, \'not_in\')]) : \'\'R\x05notIn\x12U\n\x07\x65xample\x18\x04 \x03(\x0b\x32\x1a.google.protobuf.FieldMaskB\x1f\xc2H\x1c\n\x1a\n\x12\x66ield_mask.example\x1a\x04trueR\x07\x65xample*\t\x08\xe8\x07\x10\x80\x80\x80\x80\x02\"\xe8\x17\n\x0eTimestampRules\x12\xa4\x01\n\x05\x63onst\x18\x02 \x01(\x0b\x32\x1a.google.protobuf.TimestampBr\xc2Ho\nm\n\x0ftimestamp.const\x1aZthis != getField(rules, \'const\') ? \'must equal %s\'.format([getField(rules, \'const\')]) : \'\'R\x05\x63onst\x12\xa8\x01\n\x02lt\x18\x03 \x01(\x0b\x32\x1a.google.protobuf.TimestampBz\xc2Hw\nu\n\x0ctimestamp.lt\x1a\x65!has(rules.gte) && !has(rules.gt) && this >= rules.lt? \'must be less than %s\'.format([rules.lt]) : \'\'H\x00R\x02lt\x12\xbb\x01\n\x03lte\x18\x04 \x01(\x0b\x32\x1a.google.protobuf.TimestampB\x8a\x01\xc2H\x86\x01\n\x83\x01\n\rtimestamp.lte\x1ar!has(rules.gte) && !has(rules.gt) && this > rules.lte? \'must be less than or equal to %s\'.format([rules.lte]) : \'\'H\x00R\x03lte\x12m\n\x06lt_now\x18\x07 \x01(\x08\x42T\xc2HQ\nO\n\x10timestamp.lt_now\x1a;(rules.lt_now && this > now) ? \'must be less than now\' : \'\'H\x00R\x05ltNow\x12\xad\x07\n\x02gt\x18\x05 \x01(\x0b\x32\x1a.google.protobuf.TimestampB\xfe\x06\xc2H\xfa\x06\nx\n\x0ctimestamp.gt\x1ah!has(rules.lt) && !has(rules.lte) && this <= rules.gt? \'must be greater than %s\'.format([rules.gt]) : \'\'\n\xb1\x01\n\x0ftimestamp.gt_lt\x1a\x9d\x01has(rules.lt) && rules.lt >= rules.gt && (this >= rules.lt || this <= rules.gt)? \'must be greater than %s and less than %s\'.format([rules.gt, rules.lt]) : \'\'\n\xb9\x01\n\x19timestamp.gt_lt_exclusive\x1a\x9b\x01has(rules.lt) && rules.lt < rules.gt && (rules.lt <= this && this <= rules.gt)? \'must be greater than %s or less than %s\'.format([rules.gt, rules.lt]) : \'\'\n\xc1\x01\n\x10timestamp.gt_lte\x1a\xac\x01has(rules.lte) && rules.lte >= rules.gt && (this > rules.lte || this <= rules.gt)? \'must be greater than %s and less than or equal to %s\'.format([rules.gt, rules.lte]) : \'\'\n\xc9\x01\n\x1atimestamp.gt_lte_exclusive\x1a\xaa\x01has(rules.lte) && rules.lte < rules.gt && (rules.lte < this && this <= rules.gt)? \'must be greater than %s or less than or equal to %s\'.format([rules.gt, rules.lte]) : \'\'H\x01R\x02gt\x12\xfa\x07\n\x03gte\x18\x06 \x01(\x0b\x32\x1a.google.protobuf.TimestampB\xc9\x07\xc2H\xc5\x07\n\x86\x01\n\rtimestamp.gte\x1au!has(rules.lt) && !has(rules.lte) && this < rules.gte? \'must be greater than or equal to %s\'.format([rules.gte]) : \'\'\n\xc0\x01\n\x10timestamp.gte_lt\x1a\xab\x01has(rules.lt) && rules.lt >= rules.gte && (this >= rules.lt || this < rules.gte)? \'must be greater than or equal to %s and less than %s\'.format([rules.gte, rules.lt]) : \'\'\n\xc8\x01\n\x1atimestamp.gte_lt_exclusive\x1a\xa9\x01has(rules.lt) && rules.lt < rules.gte && (rules.lt <= this && this < rules.gte)? \'must be greater than or equal to %s or less than %s\'.format([rules.gte, rules.lt]) : \'\'\n\xd0\x01\n\x11timestamp.gte_lte\x1a\xba\x01has(rules.lte) && rules.lte >= rules.gte && (this > rules.lte || this < rules.gte)? \'must be greater than or equal to %s and less than or equal to %s\'.format([rules.gte, rules.lte]) : \'\'\n\xd8\x01\n\x1btimestamp.gte_lte_exclusive\x1a\xb8\x01has(rules.lte) && rules.lte < rules.gte && (rules.lte < this && this < rules.gte)? \'must be greater than or equal to %s or less than or equal to %s\'.format([rules.gte, rules.lte]) : \'\'H\x01R\x03gte\x12p\n\x06gt_now\x18\x08 \x01(\x08\x42W\xc2HT\nR\n\x10timestamp.gt_now\x1a>(rules.gt_now && this < now) ? \'must be greater than now\' : \'\'H\x01R\x05gtNow\x12\xb9\x01\n\x06within\x18\t \x01(\x0b\x32\x19.google.protobuf.DurationB\x85\x01\xc2H\x81\x01\n\x7f\n\x10timestamp.within\x1akthis < now-rules.within || this > now+rules.within ? \'must be within %s of now\'.format([rules.within]) : \'\'R\x06within\x12T\n\x07\x65xample\x18\n \x03(\x0b\x32\x1a.google.protobuf.TimestampB\x1e\xc2H\x1b\n\x19\n\x11timestamp.example\x1a\x04trueR\x07\x65xample*\t\x08\xe8\x07\x10\x80\x80\x80\x80\x02\x42\x0b\n\tless_thanB\x0e\n\x0cgreater_than\"E\n\nViolations\x12\x37\n\nviolations\x18\x01 \x03(\x0b\x32\x17.buf.validate.ViolationR\nviolations\"\xc5\x01\n\tViolation\x12-\n\x05\x66ield\x18\x05 \x01(\x0b\x32\x17.buf.validate.FieldPathR\x05\x66ield\x12+\n\x04rule\x18\x06 \x01(\x0b\x32\x17.buf.validate.FieldPathR\x04rule\x12\x17\n\x07rule_id\x18\x02 \x01(\tR\x06ruleId\x12\x18\n\x07message\x18\x03 \x01(\tR\x07message\x12\x17\n\x07\x66or_key\x18\x04 \x01(\x08R\x06\x66orKeyJ\x04\x08\x01\x10\x02R\nfield_path\"G\n\tFieldPath\x12:\n\x08\x65lements\x18\x01 \x03(\x0b\x32\x1e.buf.validate.FieldPathElementR\x08\x65lements\"\xcc\x03\n\x10\x46ieldPathElement\x12!\n\x0c\x66ield_number\x18\x01 \x01(\x05R\x0b\x66ieldNumber\x12\x1d\n\nfield_name\x18\x02 \x01(\tR\tfieldName\x12I\n\nfield_type\x18\x03 \x01(\x0e\x32*.google.protobuf.FieldDescriptorProto.TypeR\tfieldType\x12\x45\n\x08key_type\x18\x04 \x01(\x0e\x32*.google.protobuf.FieldDescriptorProto.TypeR\x07keyType\x12I\n\nvalue_type\x18\x05 \x01(\x0e\x32*.google.protobuf.FieldDescriptorProto.TypeR\tvalueType\x12\x16\n\x05index\x18\x06 \x01(\x04H\x00R\x05index\x12\x1b\n\x08\x62ool_key\x18\x07 \x01(\x08H\x00R\x07\x62oolKey\x12\x19\n\x07int_key\x18\x08 \x01(\x03H\x00R\x06intKey\x12\x1b\n\x08uint_key\x18\t \x01(\x04H\x00R\x07uintKey\x12\x1f\n\nstring_key\x18\n \x01(\tH\x00R\tstringKeyB\x0b\n\tsubscript*\xa1\x01\n\x06Ignore\x12\x16\n\x12IGNORE_UNSPECIFIED\x10\x00\x12\x18\n\x14IGNORE_IF_ZERO_VALUE\x10\x01\x12\x11\n\rIGNORE_ALWAYS\x10\x03\"\x04\x08\x02\x10\x02*\x0cIGNORE_EMPTY*\x0eIGNORE_DEFAULT*\x17IGNORE_IF_DEFAULT_VALUE*\x15IGNORE_IF_UNPOPULATED*n\n\nKnownRegex\x12\x1b\n\x17KNOWN_REGEX_UNSPECIFIED\x10\x00\x12 \n\x1cKNOWN_REGEX_HTTP_HEADER_NAME\x10\x01\x12!\n\x1dKNOWN_REGEX_HTTP_HEADER_VALUE\x10\x02:V\n\x07message\x12\x1f.google.protobuf.MessageOptions\x18\x87\t \x01(\x0b\x32\x1a.buf.validate.MessageRulesR\x07message:N\n\x05oneof\x12\x1d.google.protobuf.OneofOptions\x18\x87\t \x01(\x0b\x32\x18.buf.validate.OneofRulesR\x05oneof:N\n\x05\x66ield\x12\x1d.google.protobuf.FieldOptions\x18\x87\t \x01(\x0b\x32\x18.buf.validate.FieldRulesR\x05\x66ield:]\n\npredefined\x12\x1d.google.protobuf.FieldOptions\x18\x88\t \x01(\x0b\x32\x1d.buf.validate.PredefinedRulesR\npredefinedB\xbb\x01\n\x10\x63om.buf.validateB\rValidateProtoP\x01ZGbuf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go/buf/validate\xa2\x02\x03\x42VX\xaa\x02\x0c\x42uf.Validate\xca\x02\x0c\x42uf\\Validate\xe2\x02\x18\x42uf\\Validate\\GPBMetadata\xea\x02\rBuf::Validate') + +_globals = globals() +_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) +_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'buf.validate.validate_pb2', _globals) +if not _descriptor._USE_C_DESCRIPTORS: + _globals['DESCRIPTOR']._loaded_options = None + _globals['DESCRIPTOR']._serialized_options = b'\n\020com.buf.validateB\rValidateProtoP\001ZGbuf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go/buf/validate\242\002\003BVX\252\002\014Buf.Validate\312\002\014Buf\\Validate\342\002\030Buf\\Validate\\GPBMetadata\352\002\rBuf::Validate' + _globals['_FLOATRULES'].fields_by_name['const']._loaded_options = None + _globals['_FLOATRULES'].fields_by_name['const']._serialized_options = b'\302Hk\ni\n\013float.const\032Zthis != getField(rules, \'const\') ? \'must equal %s\'.format([getField(rules, \'const\')]) : \'\'' + _globals['_FLOATRULES'].fields_by_name['lt']._loaded_options = None + _globals['_FLOATRULES'].fields_by_name['lt']._serialized_options = b'\302H\206\001\n\203\001\n\010float.lt\032w!has(rules.gte) && !has(rules.gt) && (this.isNan() || this >= rules.lt)? \'must be less than %s\'.format([rules.lt]) : \'\'' + _globals['_FLOATRULES'].fields_by_name['lte']._loaded_options = None + _globals['_FLOATRULES'].fields_by_name['lte']._serialized_options = b'\302H\225\001\n\222\001\n\tfloat.lte\032\204\001!has(rules.gte) && !has(rules.gt) && (this.isNan() || this > rules.lte)? \'must be less than or equal to %s\'.format([rules.lte]) : \'\'' + _globals['_FLOATRULES'].fields_by_name['gt']._loaded_options = None + _globals['_FLOATRULES'].fields_by_name['gt']._serialized_options = b'\302H\275\007\n\206\001\n\010float.gt\032z!has(rules.lt) && !has(rules.lte) && (this.isNan() || this <= rules.gt)? \'must be greater than %s\'.format([rules.gt]) : \'\'\n\275\001\n\013float.gt_lt\032\255\001has(rules.lt) && rules.lt >= rules.gt && (this.isNan() || this >= rules.lt || this <= rules.gt)? \'must be greater than %s and less than %s\'.format([rules.gt, rules.lt]) : \'\'\n\307\001\n\025float.gt_lt_exclusive\032\255\001has(rules.lt) && rules.lt < rules.gt && (this.isNan() || (rules.lt <= this && this <= rules.gt))? \'must be greater than %s or less than %s\'.format([rules.gt, rules.lt]) : \'\'\n\315\001\n\014float.gt_lte\032\274\001has(rules.lte) && rules.lte >= rules.gt && (this.isNan() || this > rules.lte || this <= rules.gt)? \'must be greater than %s and less than or equal to %s\'.format([rules.gt, rules.lte]) : \'\'\n\327\001\n\026float.gt_lte_exclusive\032\274\001has(rules.lte) && rules.lte < rules.gt && (this.isNan() || (rules.lte < this && this <= rules.gt))? \'must be greater than %s or less than or equal to %s\'.format([rules.gt, rules.lte]) : \'\'' + _globals['_FLOATRULES'].fields_by_name['gte']._loaded_options = None + _globals['_FLOATRULES'].fields_by_name['gte']._serialized_options = b'\302H\210\010\n\225\001\n\tfloat.gte\032\207\001!has(rules.lt) && !has(rules.lte) && (this.isNan() || this < rules.gte)? \'must be greater than or equal to %s\'.format([rules.gte]) : \'\'\n\314\001\n\014float.gte_lt\032\273\001has(rules.lt) && rules.lt >= rules.gte && (this.isNan() || this >= rules.lt || this < rules.gte)? \'must be greater than or equal to %s and less than %s\'.format([rules.gte, rules.lt]) : \'\'\n\326\001\n\026float.gte_lt_exclusive\032\273\001has(rules.lt) && rules.lt < rules.gte && (this.isNan() || (rules.lt <= this && this < rules.gte))? \'must be greater than or equal to %s or less than %s\'.format([rules.gte, rules.lt]) : \'\'\n\334\001\n\rfloat.gte_lte\032\312\001has(rules.lte) && rules.lte >= rules.gte && (this.isNan() || this > rules.lte || this < rules.gte)? \'must be greater than or equal to %s and less than or equal to %s\'.format([rules.gte, rules.lte]) : \'\'\n\346\001\n\027float.gte_lte_exclusive\032\312\001has(rules.lte) && rules.lte < rules.gte && (this.isNan() || (rules.lte < this && this < rules.gte))? \'must be greater than or equal to %s or less than or equal to %s\'.format([rules.gte, rules.lte]) : \'\'' + _globals['_FLOATRULES'].fields_by_name['in']._loaded_options = None + _globals['_FLOATRULES'].fields_by_name['in']._serialized_options = b'\302Hj\nh\n\010float.in\032\\!(this in getField(rules, \'in\')) ? \'must be in list %s\'.format([getField(rules, \'in\')]) : \'\'' + _globals['_FLOATRULES'].fields_by_name['not_in']._loaded_options = None + _globals['_FLOATRULES'].fields_by_name['not_in']._serialized_options = b'\302H]\n[\n\014float.not_in\032Kthis in rules.not_in ? \'must not be in list %s\'.format([rules.not_in]) : \'\'' + _globals['_FLOATRULES'].fields_by_name['finite']._loaded_options = None + _globals['_FLOATRULES'].fields_by_name['finite']._serialized_options = b'\302H\\\nZ\n\014float.finite\032Jrules.finite ? (this.isNan() || this.isInf() ? \'must be finite\' : \'\') : \'\'' + _globals['_FLOATRULES'].fields_by_name['example']._loaded_options = None + _globals['_FLOATRULES'].fields_by_name['example']._serialized_options = b'\302H\027\n\025\n\rfloat.example\032\004true' + _globals['_DOUBLERULES'].fields_by_name['const']._loaded_options = None + _globals['_DOUBLERULES'].fields_by_name['const']._serialized_options = b'\302Hl\nj\n\014double.const\032Zthis != getField(rules, \'const\') ? \'must equal %s\'.format([getField(rules, \'const\')]) : \'\'' + _globals['_DOUBLERULES'].fields_by_name['lt']._loaded_options = None + _globals['_DOUBLERULES'].fields_by_name['lt']._serialized_options = b'\302H\207\001\n\204\001\n\tdouble.lt\032w!has(rules.gte) && !has(rules.gt) && (this.isNan() || this >= rules.lt)? \'must be less than %s\'.format([rules.lt]) : \'\'' + _globals['_DOUBLERULES'].fields_by_name['lte']._loaded_options = None + _globals['_DOUBLERULES'].fields_by_name['lte']._serialized_options = b'\302H\226\001\n\223\001\n\ndouble.lte\032\204\001!has(rules.gte) && !has(rules.gt) && (this.isNan() || this > rules.lte)? \'must be less than or equal to %s\'.format([rules.lte]) : \'\'' + _globals['_DOUBLERULES'].fields_by_name['gt']._loaded_options = None + _globals['_DOUBLERULES'].fields_by_name['gt']._serialized_options = b'\302H\302\007\n\207\001\n\tdouble.gt\032z!has(rules.lt) && !has(rules.lte) && (this.isNan() || this <= rules.gt)? \'must be greater than %s\'.format([rules.gt]) : \'\'\n\276\001\n\014double.gt_lt\032\255\001has(rules.lt) && rules.lt >= rules.gt && (this.isNan() || this >= rules.lt || this <= rules.gt)? \'must be greater than %s and less than %s\'.format([rules.gt, rules.lt]) : \'\'\n\310\001\n\026double.gt_lt_exclusive\032\255\001has(rules.lt) && rules.lt < rules.gt && (this.isNan() || (rules.lt <= this && this <= rules.gt))? \'must be greater than %s or less than %s\'.format([rules.gt, rules.lt]) : \'\'\n\316\001\n\rdouble.gt_lte\032\274\001has(rules.lte) && rules.lte >= rules.gt && (this.isNan() || this > rules.lte || this <= rules.gt)? \'must be greater than %s and less than or equal to %s\'.format([rules.gt, rules.lte]) : \'\'\n\330\001\n\027double.gt_lte_exclusive\032\274\001has(rules.lte) && rules.lte < rules.gt && (this.isNan() || (rules.lte < this && this <= rules.gt))? \'must be greater than %s or less than or equal to %s\'.format([rules.gt, rules.lte]) : \'\'' + _globals['_DOUBLERULES'].fields_by_name['gte']._loaded_options = None + _globals['_DOUBLERULES'].fields_by_name['gte']._serialized_options = b'\302H\215\010\n\226\001\n\ndouble.gte\032\207\001!has(rules.lt) && !has(rules.lte) && (this.isNan() || this < rules.gte)? \'must be greater than or equal to %s\'.format([rules.gte]) : \'\'\n\315\001\n\rdouble.gte_lt\032\273\001has(rules.lt) && rules.lt >= rules.gte && (this.isNan() || this >= rules.lt || this < rules.gte)? \'must be greater than or equal to %s and less than %s\'.format([rules.gte, rules.lt]) : \'\'\n\327\001\n\027double.gte_lt_exclusive\032\273\001has(rules.lt) && rules.lt < rules.gte && (this.isNan() || (rules.lt <= this && this < rules.gte))? \'must be greater than or equal to %s or less than %s\'.format([rules.gte, rules.lt]) : \'\'\n\335\001\n\016double.gte_lte\032\312\001has(rules.lte) && rules.lte >= rules.gte && (this.isNan() || this > rules.lte || this < rules.gte)? \'must be greater than or equal to %s and less than or equal to %s\'.format([rules.gte, rules.lte]) : \'\'\n\347\001\n\030double.gte_lte_exclusive\032\312\001has(rules.lte) && rules.lte < rules.gte && (this.isNan() || (rules.lte < this && this < rules.gte))? \'must be greater than or equal to %s or less than or equal to %s\'.format([rules.gte, rules.lte]) : \'\'' + _globals['_DOUBLERULES'].fields_by_name['in']._loaded_options = None + _globals['_DOUBLERULES'].fields_by_name['in']._serialized_options = b'\302Hk\ni\n\tdouble.in\032\\!(this in getField(rules, \'in\')) ? \'must be in list %s\'.format([getField(rules, \'in\')]) : \'\'' + _globals['_DOUBLERULES'].fields_by_name['not_in']._loaded_options = None + _globals['_DOUBLERULES'].fields_by_name['not_in']._serialized_options = b'\302H^\n\\\n\rdouble.not_in\032Kthis in rules.not_in ? \'must not be in list %s\'.format([rules.not_in]) : \'\'' + _globals['_DOUBLERULES'].fields_by_name['finite']._loaded_options = None + _globals['_DOUBLERULES'].fields_by_name['finite']._serialized_options = b'\302H]\n[\n\rdouble.finite\032Jrules.finite ? (this.isNan() || this.isInf() ? \'must be finite\' : \'\') : \'\'' + _globals['_DOUBLERULES'].fields_by_name['example']._loaded_options = None + _globals['_DOUBLERULES'].fields_by_name['example']._serialized_options = b'\302H\030\n\026\n\016double.example\032\004true' + _globals['_INT32RULES'].fields_by_name['const']._loaded_options = None + _globals['_INT32RULES'].fields_by_name['const']._serialized_options = b'\302Hk\ni\n\013int32.const\032Zthis != getField(rules, \'const\') ? \'must equal %s\'.format([getField(rules, \'const\')]) : \'\'' + _globals['_INT32RULES'].fields_by_name['lt']._loaded_options = None + _globals['_INT32RULES'].fields_by_name['lt']._serialized_options = b'\302Hs\nq\n\010int32.lt\032e!has(rules.gte) && !has(rules.gt) && this >= rules.lt? \'must be less than %s\'.format([rules.lt]) : \'\'' + _globals['_INT32RULES'].fields_by_name['lte']._loaded_options = None + _globals['_INT32RULES'].fields_by_name['lte']._serialized_options = b'\302H\201\001\n\177\n\tint32.lte\032r!has(rules.gte) && !has(rules.gt) && this > rules.lte? \'must be less than or equal to %s\'.format([rules.lte]) : \'\'' + _globals['_INT32RULES'].fields_by_name['gt']._loaded_options = None + _globals['_INT32RULES'].fields_by_name['gt']._serialized_options = b'\302H\346\006\nt\n\010int32.gt\032h!has(rules.lt) && !has(rules.lte) && this <= rules.gt? \'must be greater than %s\'.format([rules.gt]) : \'\'\n\255\001\n\013int32.gt_lt\032\235\001has(rules.lt) && rules.lt >= rules.gt && (this >= rules.lt || this <= rules.gt)? \'must be greater than %s and less than %s\'.format([rules.gt, rules.lt]) : \'\'\n\265\001\n\025int32.gt_lt_exclusive\032\233\001has(rules.lt) && rules.lt < rules.gt && (rules.lt <= this && this <= rules.gt)? \'must be greater than %s or less than %s\'.format([rules.gt, rules.lt]) : \'\'\n\275\001\n\014int32.gt_lte\032\254\001has(rules.lte) && rules.lte >= rules.gt && (this > rules.lte || this <= rules.gt)? \'must be greater than %s and less than or equal to %s\'.format([rules.gt, rules.lte]) : \'\'\n\305\001\n\026int32.gt_lte_exclusive\032\252\001has(rules.lte) && rules.lte < rules.gt && (rules.lte < this && this <= rules.gt)? \'must be greater than %s or less than or equal to %s\'.format([rules.gt, rules.lte]) : \'\'' + _globals['_INT32RULES'].fields_by_name['gte']._loaded_options = None + _globals['_INT32RULES'].fields_by_name['gte']._serialized_options = b'\302H\261\007\n\202\001\n\tint32.gte\032u!has(rules.lt) && !has(rules.lte) && this < rules.gte? \'must be greater than or equal to %s\'.format([rules.gte]) : \'\'\n\274\001\n\014int32.gte_lt\032\253\001has(rules.lt) && rules.lt >= rules.gte && (this >= rules.lt || this < rules.gte)? \'must be greater than or equal to %s and less than %s\'.format([rules.gte, rules.lt]) : \'\'\n\304\001\n\026int32.gte_lt_exclusive\032\251\001has(rules.lt) && rules.lt < rules.gte && (rules.lt <= this && this < rules.gte)? \'must be greater than or equal to %s or less than %s\'.format([rules.gte, rules.lt]) : \'\'\n\314\001\n\rint32.gte_lte\032\272\001has(rules.lte) && rules.lte >= rules.gte && (this > rules.lte || this < rules.gte)? \'must be greater than or equal to %s and less than or equal to %s\'.format([rules.gte, rules.lte]) : \'\'\n\324\001\n\027int32.gte_lte_exclusive\032\270\001has(rules.lte) && rules.lte < rules.gte && (rules.lte < this && this < rules.gte)? \'must be greater than or equal to %s or less than or equal to %s\'.format([rules.gte, rules.lte]) : \'\'' + _globals['_INT32RULES'].fields_by_name['in']._loaded_options = None + _globals['_INT32RULES'].fields_by_name['in']._serialized_options = b'\302Hj\nh\n\010int32.in\032\\!(this in getField(rules, \'in\')) ? \'must be in list %s\'.format([getField(rules, \'in\')]) : \'\'' + _globals['_INT32RULES'].fields_by_name['not_in']._loaded_options = None + _globals['_INT32RULES'].fields_by_name['not_in']._serialized_options = b'\302H]\n[\n\014int32.not_in\032Kthis in rules.not_in ? \'must not be in list %s\'.format([rules.not_in]) : \'\'' + _globals['_INT32RULES'].fields_by_name['example']._loaded_options = None + _globals['_INT32RULES'].fields_by_name['example']._serialized_options = b'\302H\027\n\025\n\rint32.example\032\004true' + _globals['_INT64RULES'].fields_by_name['const']._loaded_options = None + _globals['_INT64RULES'].fields_by_name['const']._serialized_options = b'\302Hk\ni\n\013int64.const\032Zthis != getField(rules, \'const\') ? \'must equal %s\'.format([getField(rules, \'const\')]) : \'\'' + _globals['_INT64RULES'].fields_by_name['lt']._loaded_options = None + _globals['_INT64RULES'].fields_by_name['lt']._serialized_options = b'\302Hs\nq\n\010int64.lt\032e!has(rules.gte) && !has(rules.gt) && this >= rules.lt? \'must be less than %s\'.format([rules.lt]) : \'\'' + _globals['_INT64RULES'].fields_by_name['lte']._loaded_options = None + _globals['_INT64RULES'].fields_by_name['lte']._serialized_options = b'\302H\201\001\n\177\n\tint64.lte\032r!has(rules.gte) && !has(rules.gt) && this > rules.lte? \'must be less than or equal to %s\'.format([rules.lte]) : \'\'' + _globals['_INT64RULES'].fields_by_name['gt']._loaded_options = None + _globals['_INT64RULES'].fields_by_name['gt']._serialized_options = b'\302H\346\006\nt\n\010int64.gt\032h!has(rules.lt) && !has(rules.lte) && this <= rules.gt? \'must be greater than %s\'.format([rules.gt]) : \'\'\n\255\001\n\013int64.gt_lt\032\235\001has(rules.lt) && rules.lt >= rules.gt && (this >= rules.lt || this <= rules.gt)? \'must be greater than %s and less than %s\'.format([rules.gt, rules.lt]) : \'\'\n\265\001\n\025int64.gt_lt_exclusive\032\233\001has(rules.lt) && rules.lt < rules.gt && (rules.lt <= this && this <= rules.gt)? \'must be greater than %s or less than %s\'.format([rules.gt, rules.lt]) : \'\'\n\275\001\n\014int64.gt_lte\032\254\001has(rules.lte) && rules.lte >= rules.gt && (this > rules.lte || this <= rules.gt)? \'must be greater than %s and less than or equal to %s\'.format([rules.gt, rules.lte]) : \'\'\n\305\001\n\026int64.gt_lte_exclusive\032\252\001has(rules.lte) && rules.lte < rules.gt && (rules.lte < this && this <= rules.gt)? \'must be greater than %s or less than or equal to %s\'.format([rules.gt, rules.lte]) : \'\'' + _globals['_INT64RULES'].fields_by_name['gte']._loaded_options = None + _globals['_INT64RULES'].fields_by_name['gte']._serialized_options = b'\302H\261\007\n\202\001\n\tint64.gte\032u!has(rules.lt) && !has(rules.lte) && this < rules.gte? \'must be greater than or equal to %s\'.format([rules.gte]) : \'\'\n\274\001\n\014int64.gte_lt\032\253\001has(rules.lt) && rules.lt >= rules.gte && (this >= rules.lt || this < rules.gte)? \'must be greater than or equal to %s and less than %s\'.format([rules.gte, rules.lt]) : \'\'\n\304\001\n\026int64.gte_lt_exclusive\032\251\001has(rules.lt) && rules.lt < rules.gte && (rules.lt <= this && this < rules.gte)? \'must be greater than or equal to %s or less than %s\'.format([rules.gte, rules.lt]) : \'\'\n\314\001\n\rint64.gte_lte\032\272\001has(rules.lte) && rules.lte >= rules.gte && (this > rules.lte || this < rules.gte)? \'must be greater than or equal to %s and less than or equal to %s\'.format([rules.gte, rules.lte]) : \'\'\n\324\001\n\027int64.gte_lte_exclusive\032\270\001has(rules.lte) && rules.lte < rules.gte && (rules.lte < this && this < rules.gte)? \'must be greater than or equal to %s or less than or equal to %s\'.format([rules.gte, rules.lte]) : \'\'' + _globals['_INT64RULES'].fields_by_name['in']._loaded_options = None + _globals['_INT64RULES'].fields_by_name['in']._serialized_options = b'\302Hj\nh\n\010int64.in\032\\!(this in getField(rules, \'in\')) ? \'must be in list %s\'.format([getField(rules, \'in\')]) : \'\'' + _globals['_INT64RULES'].fields_by_name['not_in']._loaded_options = None + _globals['_INT64RULES'].fields_by_name['not_in']._serialized_options = b'\302H]\n[\n\014int64.not_in\032Kthis in rules.not_in ? \'must not be in list %s\'.format([rules.not_in]) : \'\'' + _globals['_INT64RULES'].fields_by_name['example']._loaded_options = None + _globals['_INT64RULES'].fields_by_name['example']._serialized_options = b'\302H\027\n\025\n\rint64.example\032\004true' + _globals['_UINT32RULES'].fields_by_name['const']._loaded_options = None + _globals['_UINT32RULES'].fields_by_name['const']._serialized_options = b'\302Hl\nj\n\014uint32.const\032Zthis != getField(rules, \'const\') ? \'must equal %s\'.format([getField(rules, \'const\')]) : \'\'' + _globals['_UINT32RULES'].fields_by_name['lt']._loaded_options = None + _globals['_UINT32RULES'].fields_by_name['lt']._serialized_options = b'\302Ht\nr\n\tuint32.lt\032e!has(rules.gte) && !has(rules.gt) && this >= rules.lt? \'must be less than %s\'.format([rules.lt]) : \'\'' + _globals['_UINT32RULES'].fields_by_name['lte']._loaded_options = None + _globals['_UINT32RULES'].fields_by_name['lte']._serialized_options = b'\302H\203\001\n\200\001\n\nuint32.lte\032r!has(rules.gte) && !has(rules.gt) && this > rules.lte? \'must be less than or equal to %s\'.format([rules.lte]) : \'\'' + _globals['_UINT32RULES'].fields_by_name['gt']._loaded_options = None + _globals['_UINT32RULES'].fields_by_name['gt']._serialized_options = b'\302H\353\006\nu\n\tuint32.gt\032h!has(rules.lt) && !has(rules.lte) && this <= rules.gt? \'must be greater than %s\'.format([rules.gt]) : \'\'\n\256\001\n\014uint32.gt_lt\032\235\001has(rules.lt) && rules.lt >= rules.gt && (this >= rules.lt || this <= rules.gt)? \'must be greater than %s and less than %s\'.format([rules.gt, rules.lt]) : \'\'\n\266\001\n\026uint32.gt_lt_exclusive\032\233\001has(rules.lt) && rules.lt < rules.gt && (rules.lt <= this && this <= rules.gt)? \'must be greater than %s or less than %s\'.format([rules.gt, rules.lt]) : \'\'\n\276\001\n\ruint32.gt_lte\032\254\001has(rules.lte) && rules.lte >= rules.gt && (this > rules.lte || this <= rules.gt)? \'must be greater than %s and less than or equal to %s\'.format([rules.gt, rules.lte]) : \'\'\n\306\001\n\027uint32.gt_lte_exclusive\032\252\001has(rules.lte) && rules.lte < rules.gt && (rules.lte < this && this <= rules.gt)? \'must be greater than %s or less than or equal to %s\'.format([rules.gt, rules.lte]) : \'\'' + _globals['_UINT32RULES'].fields_by_name['gte']._loaded_options = None + _globals['_UINT32RULES'].fields_by_name['gte']._serialized_options = b'\302H\266\007\n\203\001\n\nuint32.gte\032u!has(rules.lt) && !has(rules.lte) && this < rules.gte? \'must be greater than or equal to %s\'.format([rules.gte]) : \'\'\n\275\001\n\ruint32.gte_lt\032\253\001has(rules.lt) && rules.lt >= rules.gte && (this >= rules.lt || this < rules.gte)? \'must be greater than or equal to %s and less than %s\'.format([rules.gte, rules.lt]) : \'\'\n\305\001\n\027uint32.gte_lt_exclusive\032\251\001has(rules.lt) && rules.lt < rules.gte && (rules.lt <= this && this < rules.gte)? \'must be greater than or equal to %s or less than %s\'.format([rules.gte, rules.lt]) : \'\'\n\315\001\n\016uint32.gte_lte\032\272\001has(rules.lte) && rules.lte >= rules.gte && (this > rules.lte || this < rules.gte)? \'must be greater than or equal to %s and less than or equal to %s\'.format([rules.gte, rules.lte]) : \'\'\n\325\001\n\030uint32.gte_lte_exclusive\032\270\001has(rules.lte) && rules.lte < rules.gte && (rules.lte < this && this < rules.gte)? \'must be greater than or equal to %s or less than or equal to %s\'.format([rules.gte, rules.lte]) : \'\'' + _globals['_UINT32RULES'].fields_by_name['in']._loaded_options = None + _globals['_UINT32RULES'].fields_by_name['in']._serialized_options = b'\302Hk\ni\n\tuint32.in\032\\!(this in getField(rules, \'in\')) ? \'must be in list %s\'.format([getField(rules, \'in\')]) : \'\'' + _globals['_UINT32RULES'].fields_by_name['not_in']._loaded_options = None + _globals['_UINT32RULES'].fields_by_name['not_in']._serialized_options = b'\302H^\n\\\n\ruint32.not_in\032Kthis in rules.not_in ? \'must not be in list %s\'.format([rules.not_in]) : \'\'' + _globals['_UINT32RULES'].fields_by_name['example']._loaded_options = None + _globals['_UINT32RULES'].fields_by_name['example']._serialized_options = b'\302H\030\n\026\n\016uint32.example\032\004true' + _globals['_UINT64RULES'].fields_by_name['const']._loaded_options = None + _globals['_UINT64RULES'].fields_by_name['const']._serialized_options = b'\302Hl\nj\n\014uint64.const\032Zthis != getField(rules, \'const\') ? \'must equal %s\'.format([getField(rules, \'const\')]) : \'\'' + _globals['_UINT64RULES'].fields_by_name['lt']._loaded_options = None + _globals['_UINT64RULES'].fields_by_name['lt']._serialized_options = b'\302Ht\nr\n\tuint64.lt\032e!has(rules.gte) && !has(rules.gt) && this >= rules.lt? \'must be less than %s\'.format([rules.lt]) : \'\'' + _globals['_UINT64RULES'].fields_by_name['lte']._loaded_options = None + _globals['_UINT64RULES'].fields_by_name['lte']._serialized_options = b'\302H\203\001\n\200\001\n\nuint64.lte\032r!has(rules.gte) && !has(rules.gt) && this > rules.lte? \'must be less than or equal to %s\'.format([rules.lte]) : \'\'' + _globals['_UINT64RULES'].fields_by_name['gt']._loaded_options = None + _globals['_UINT64RULES'].fields_by_name['gt']._serialized_options = b'\302H\353\006\nu\n\tuint64.gt\032h!has(rules.lt) && !has(rules.lte) && this <= rules.gt? \'must be greater than %s\'.format([rules.gt]) : \'\'\n\256\001\n\014uint64.gt_lt\032\235\001has(rules.lt) && rules.lt >= rules.gt && (this >= rules.lt || this <= rules.gt)? \'must be greater than %s and less than %s\'.format([rules.gt, rules.lt]) : \'\'\n\266\001\n\026uint64.gt_lt_exclusive\032\233\001has(rules.lt) && rules.lt < rules.gt && (rules.lt <= this && this <= rules.gt)? \'must be greater than %s or less than %s\'.format([rules.gt, rules.lt]) : \'\'\n\276\001\n\ruint64.gt_lte\032\254\001has(rules.lte) && rules.lte >= rules.gt && (this > rules.lte || this <= rules.gt)? \'must be greater than %s and less than or equal to %s\'.format([rules.gt, rules.lte]) : \'\'\n\306\001\n\027uint64.gt_lte_exclusive\032\252\001has(rules.lte) && rules.lte < rules.gt && (rules.lte < this && this <= rules.gt)? \'must be greater than %s or less than or equal to %s\'.format([rules.gt, rules.lte]) : \'\'' + _globals['_UINT64RULES'].fields_by_name['gte']._loaded_options = None + _globals['_UINT64RULES'].fields_by_name['gte']._serialized_options = b'\302H\266\007\n\203\001\n\nuint64.gte\032u!has(rules.lt) && !has(rules.lte) && this < rules.gte? \'must be greater than or equal to %s\'.format([rules.gte]) : \'\'\n\275\001\n\ruint64.gte_lt\032\253\001has(rules.lt) && rules.lt >= rules.gte && (this >= rules.lt || this < rules.gte)? \'must be greater than or equal to %s and less than %s\'.format([rules.gte, rules.lt]) : \'\'\n\305\001\n\027uint64.gte_lt_exclusive\032\251\001has(rules.lt) && rules.lt < rules.gte && (rules.lt <= this && this < rules.gte)? \'must be greater than or equal to %s or less than %s\'.format([rules.gte, rules.lt]) : \'\'\n\315\001\n\016uint64.gte_lte\032\272\001has(rules.lte) && rules.lte >= rules.gte && (this > rules.lte || this < rules.gte)? \'must be greater than or equal to %s and less than or equal to %s\'.format([rules.gte, rules.lte]) : \'\'\n\325\001\n\030uint64.gte_lte_exclusive\032\270\001has(rules.lte) && rules.lte < rules.gte && (rules.lte < this && this < rules.gte)? \'must be greater than or equal to %s or less than or equal to %s\'.format([rules.gte, rules.lte]) : \'\'' + _globals['_UINT64RULES'].fields_by_name['in']._loaded_options = None + _globals['_UINT64RULES'].fields_by_name['in']._serialized_options = b'\302Hk\ni\n\tuint64.in\032\\!(this in getField(rules, \'in\')) ? \'must be in list %s\'.format([getField(rules, \'in\')]) : \'\'' + _globals['_UINT64RULES'].fields_by_name['not_in']._loaded_options = None + _globals['_UINT64RULES'].fields_by_name['not_in']._serialized_options = b'\302H^\n\\\n\ruint64.not_in\032Kthis in rules.not_in ? \'must not be in list %s\'.format([rules.not_in]) : \'\'' + _globals['_UINT64RULES'].fields_by_name['example']._loaded_options = None + _globals['_UINT64RULES'].fields_by_name['example']._serialized_options = b'\302H\030\n\026\n\016uint64.example\032\004true' + _globals['_SINT32RULES'].fields_by_name['const']._loaded_options = None + _globals['_SINT32RULES'].fields_by_name['const']._serialized_options = b'\302Hl\nj\n\014sint32.const\032Zthis != getField(rules, \'const\') ? \'must equal %s\'.format([getField(rules, \'const\')]) : \'\'' + _globals['_SINT32RULES'].fields_by_name['lt']._loaded_options = None + _globals['_SINT32RULES'].fields_by_name['lt']._serialized_options = b'\302Ht\nr\n\tsint32.lt\032e!has(rules.gte) && !has(rules.gt) && this >= rules.lt? \'must be less than %s\'.format([rules.lt]) : \'\'' + _globals['_SINT32RULES'].fields_by_name['lte']._loaded_options = None + _globals['_SINT32RULES'].fields_by_name['lte']._serialized_options = b'\302H\203\001\n\200\001\n\nsint32.lte\032r!has(rules.gte) && !has(rules.gt) && this > rules.lte? \'must be less than or equal to %s\'.format([rules.lte]) : \'\'' + _globals['_SINT32RULES'].fields_by_name['gt']._loaded_options = None + _globals['_SINT32RULES'].fields_by_name['gt']._serialized_options = b'\302H\353\006\nu\n\tsint32.gt\032h!has(rules.lt) && !has(rules.lte) && this <= rules.gt? \'must be greater than %s\'.format([rules.gt]) : \'\'\n\256\001\n\014sint32.gt_lt\032\235\001has(rules.lt) && rules.lt >= rules.gt && (this >= rules.lt || this <= rules.gt)? \'must be greater than %s and less than %s\'.format([rules.gt, rules.lt]) : \'\'\n\266\001\n\026sint32.gt_lt_exclusive\032\233\001has(rules.lt) && rules.lt < rules.gt && (rules.lt <= this && this <= rules.gt)? \'must be greater than %s or less than %s\'.format([rules.gt, rules.lt]) : \'\'\n\276\001\n\rsint32.gt_lte\032\254\001has(rules.lte) && rules.lte >= rules.gt && (this > rules.lte || this <= rules.gt)? \'must be greater than %s and less than or equal to %s\'.format([rules.gt, rules.lte]) : \'\'\n\306\001\n\027sint32.gt_lte_exclusive\032\252\001has(rules.lte) && rules.lte < rules.gt && (rules.lte < this && this <= rules.gt)? \'must be greater than %s or less than or equal to %s\'.format([rules.gt, rules.lte]) : \'\'' + _globals['_SINT32RULES'].fields_by_name['gte']._loaded_options = None + _globals['_SINT32RULES'].fields_by_name['gte']._serialized_options = b'\302H\266\007\n\203\001\n\nsint32.gte\032u!has(rules.lt) && !has(rules.lte) && this < rules.gte? \'must be greater than or equal to %s\'.format([rules.gte]) : \'\'\n\275\001\n\rsint32.gte_lt\032\253\001has(rules.lt) && rules.lt >= rules.gte && (this >= rules.lt || this < rules.gte)? \'must be greater than or equal to %s and less than %s\'.format([rules.gte, rules.lt]) : \'\'\n\305\001\n\027sint32.gte_lt_exclusive\032\251\001has(rules.lt) && rules.lt < rules.gte && (rules.lt <= this && this < rules.gte)? \'must be greater than or equal to %s or less than %s\'.format([rules.gte, rules.lt]) : \'\'\n\315\001\n\016sint32.gte_lte\032\272\001has(rules.lte) && rules.lte >= rules.gte && (this > rules.lte || this < rules.gte)? \'must be greater than or equal to %s and less than or equal to %s\'.format([rules.gte, rules.lte]) : \'\'\n\325\001\n\030sint32.gte_lte_exclusive\032\270\001has(rules.lte) && rules.lte < rules.gte && (rules.lte < this && this < rules.gte)? \'must be greater than or equal to %s or less than or equal to %s\'.format([rules.gte, rules.lte]) : \'\'' + _globals['_SINT32RULES'].fields_by_name['in']._loaded_options = None + _globals['_SINT32RULES'].fields_by_name['in']._serialized_options = b'\302Hk\ni\n\tsint32.in\032\\!(this in getField(rules, \'in\')) ? \'must be in list %s\'.format([getField(rules, \'in\')]) : \'\'' + _globals['_SINT32RULES'].fields_by_name['not_in']._loaded_options = None + _globals['_SINT32RULES'].fields_by_name['not_in']._serialized_options = b'\302H^\n\\\n\rsint32.not_in\032Kthis in rules.not_in ? \'must not be in list %s\'.format([rules.not_in]) : \'\'' + _globals['_SINT32RULES'].fields_by_name['example']._loaded_options = None + _globals['_SINT32RULES'].fields_by_name['example']._serialized_options = b'\302H\030\n\026\n\016sint32.example\032\004true' + _globals['_SINT64RULES'].fields_by_name['const']._loaded_options = None + _globals['_SINT64RULES'].fields_by_name['const']._serialized_options = b'\302Hl\nj\n\014sint64.const\032Zthis != getField(rules, \'const\') ? \'must equal %s\'.format([getField(rules, \'const\')]) : \'\'' + _globals['_SINT64RULES'].fields_by_name['lt']._loaded_options = None + _globals['_SINT64RULES'].fields_by_name['lt']._serialized_options = b'\302Ht\nr\n\tsint64.lt\032e!has(rules.gte) && !has(rules.gt) && this >= rules.lt? \'must be less than %s\'.format([rules.lt]) : \'\'' + _globals['_SINT64RULES'].fields_by_name['lte']._loaded_options = None + _globals['_SINT64RULES'].fields_by_name['lte']._serialized_options = b'\302H\203\001\n\200\001\n\nsint64.lte\032r!has(rules.gte) && !has(rules.gt) && this > rules.lte? \'must be less than or equal to %s\'.format([rules.lte]) : \'\'' + _globals['_SINT64RULES'].fields_by_name['gt']._loaded_options = None + _globals['_SINT64RULES'].fields_by_name['gt']._serialized_options = b'\302H\353\006\nu\n\tsint64.gt\032h!has(rules.lt) && !has(rules.lte) && this <= rules.gt? \'must be greater than %s\'.format([rules.gt]) : \'\'\n\256\001\n\014sint64.gt_lt\032\235\001has(rules.lt) && rules.lt >= rules.gt && (this >= rules.lt || this <= rules.gt)? \'must be greater than %s and less than %s\'.format([rules.gt, rules.lt]) : \'\'\n\266\001\n\026sint64.gt_lt_exclusive\032\233\001has(rules.lt) && rules.lt < rules.gt && (rules.lt <= this && this <= rules.gt)? \'must be greater than %s or less than %s\'.format([rules.gt, rules.lt]) : \'\'\n\276\001\n\rsint64.gt_lte\032\254\001has(rules.lte) && rules.lte >= rules.gt && (this > rules.lte || this <= rules.gt)? \'must be greater than %s and less than or equal to %s\'.format([rules.gt, rules.lte]) : \'\'\n\306\001\n\027sint64.gt_lte_exclusive\032\252\001has(rules.lte) && rules.lte < rules.gt && (rules.lte < this && this <= rules.gt)? \'must be greater than %s or less than or equal to %s\'.format([rules.gt, rules.lte]) : \'\'' + _globals['_SINT64RULES'].fields_by_name['gte']._loaded_options = None + _globals['_SINT64RULES'].fields_by_name['gte']._serialized_options = b'\302H\266\007\n\203\001\n\nsint64.gte\032u!has(rules.lt) && !has(rules.lte) && this < rules.gte? \'must be greater than or equal to %s\'.format([rules.gte]) : \'\'\n\275\001\n\rsint64.gte_lt\032\253\001has(rules.lt) && rules.lt >= rules.gte && (this >= rules.lt || this < rules.gte)? \'must be greater than or equal to %s and less than %s\'.format([rules.gte, rules.lt]) : \'\'\n\305\001\n\027sint64.gte_lt_exclusive\032\251\001has(rules.lt) && rules.lt < rules.gte && (rules.lt <= this && this < rules.gte)? \'must be greater than or equal to %s or less than %s\'.format([rules.gte, rules.lt]) : \'\'\n\315\001\n\016sint64.gte_lte\032\272\001has(rules.lte) && rules.lte >= rules.gte && (this > rules.lte || this < rules.gte)? \'must be greater than or equal to %s and less than or equal to %s\'.format([rules.gte, rules.lte]) : \'\'\n\325\001\n\030sint64.gte_lte_exclusive\032\270\001has(rules.lte) && rules.lte < rules.gte && (rules.lte < this && this < rules.gte)? \'must be greater than or equal to %s or less than or equal to %s\'.format([rules.gte, rules.lte]) : \'\'' + _globals['_SINT64RULES'].fields_by_name['in']._loaded_options = None + _globals['_SINT64RULES'].fields_by_name['in']._serialized_options = b'\302Hk\ni\n\tsint64.in\032\\!(this in getField(rules, \'in\')) ? \'must be in list %s\'.format([getField(rules, \'in\')]) : \'\'' + _globals['_SINT64RULES'].fields_by_name['not_in']._loaded_options = None + _globals['_SINT64RULES'].fields_by_name['not_in']._serialized_options = b'\302H^\n\\\n\rsint64.not_in\032Kthis in rules.not_in ? \'must not be in list %s\'.format([rules.not_in]) : \'\'' + _globals['_SINT64RULES'].fields_by_name['example']._loaded_options = None + _globals['_SINT64RULES'].fields_by_name['example']._serialized_options = b'\302H\030\n\026\n\016sint64.example\032\004true' + _globals['_FIXED32RULES'].fields_by_name['const']._loaded_options = None + _globals['_FIXED32RULES'].fields_by_name['const']._serialized_options = b'\302Hm\nk\n\rfixed32.const\032Zthis != getField(rules, \'const\') ? \'must equal %s\'.format([getField(rules, \'const\')]) : \'\'' + _globals['_FIXED32RULES'].fields_by_name['lt']._loaded_options = None + _globals['_FIXED32RULES'].fields_by_name['lt']._serialized_options = b'\302Hu\ns\n\nfixed32.lt\032e!has(rules.gte) && !has(rules.gt) && this >= rules.lt? \'must be less than %s\'.format([rules.lt]) : \'\'' + _globals['_FIXED32RULES'].fields_by_name['lte']._loaded_options = None + _globals['_FIXED32RULES'].fields_by_name['lte']._serialized_options = b'\302H\204\001\n\201\001\n\013fixed32.lte\032r!has(rules.gte) && !has(rules.gt) && this > rules.lte? \'must be less than or equal to %s\'.format([rules.lte]) : \'\'' + _globals['_FIXED32RULES'].fields_by_name['gt']._loaded_options = None + _globals['_FIXED32RULES'].fields_by_name['gt']._serialized_options = b'\302H\360\006\nv\n\nfixed32.gt\032h!has(rules.lt) && !has(rules.lte) && this <= rules.gt? \'must be greater than %s\'.format([rules.gt]) : \'\'\n\257\001\n\rfixed32.gt_lt\032\235\001has(rules.lt) && rules.lt >= rules.gt && (this >= rules.lt || this <= rules.gt)? \'must be greater than %s and less than %s\'.format([rules.gt, rules.lt]) : \'\'\n\267\001\n\027fixed32.gt_lt_exclusive\032\233\001has(rules.lt) && rules.lt < rules.gt && (rules.lt <= this && this <= rules.gt)? \'must be greater than %s or less than %s\'.format([rules.gt, rules.lt]) : \'\'\n\277\001\n\016fixed32.gt_lte\032\254\001has(rules.lte) && rules.lte >= rules.gt && (this > rules.lte || this <= rules.gt)? \'must be greater than %s and less than or equal to %s\'.format([rules.gt, rules.lte]) : \'\'\n\307\001\n\030fixed32.gt_lte_exclusive\032\252\001has(rules.lte) && rules.lte < rules.gt && (rules.lte < this && this <= rules.gt)? \'must be greater than %s or less than or equal to %s\'.format([rules.gt, rules.lte]) : \'\'' + _globals['_FIXED32RULES'].fields_by_name['gte']._loaded_options = None + _globals['_FIXED32RULES'].fields_by_name['gte']._serialized_options = b'\302H\273\007\n\204\001\n\013fixed32.gte\032u!has(rules.lt) && !has(rules.lte) && this < rules.gte? \'must be greater than or equal to %s\'.format([rules.gte]) : \'\'\n\276\001\n\016fixed32.gte_lt\032\253\001has(rules.lt) && rules.lt >= rules.gte && (this >= rules.lt || this < rules.gte)? \'must be greater than or equal to %s and less than %s\'.format([rules.gte, rules.lt]) : \'\'\n\306\001\n\030fixed32.gte_lt_exclusive\032\251\001has(rules.lt) && rules.lt < rules.gte && (rules.lt <= this && this < rules.gte)? \'must be greater than or equal to %s or less than %s\'.format([rules.gte, rules.lt]) : \'\'\n\316\001\n\017fixed32.gte_lte\032\272\001has(rules.lte) && rules.lte >= rules.gte && (this > rules.lte || this < rules.gte)? \'must be greater than or equal to %s and less than or equal to %s\'.format([rules.gte, rules.lte]) : \'\'\n\326\001\n\031fixed32.gte_lte_exclusive\032\270\001has(rules.lte) && rules.lte < rules.gte && (rules.lte < this && this < rules.gte)? \'must be greater than or equal to %s or less than or equal to %s\'.format([rules.gte, rules.lte]) : \'\'' + _globals['_FIXED32RULES'].fields_by_name['in']._loaded_options = None + _globals['_FIXED32RULES'].fields_by_name['in']._serialized_options = b'\302Hl\nj\n\nfixed32.in\032\\!(this in getField(rules, \'in\')) ? \'must be in list %s\'.format([getField(rules, \'in\')]) : \'\'' + _globals['_FIXED32RULES'].fields_by_name['not_in']._loaded_options = None + _globals['_FIXED32RULES'].fields_by_name['not_in']._serialized_options = b'\302H_\n]\n\016fixed32.not_in\032Kthis in rules.not_in ? \'must not be in list %s\'.format([rules.not_in]) : \'\'' + _globals['_FIXED32RULES'].fields_by_name['example']._loaded_options = None + _globals['_FIXED32RULES'].fields_by_name['example']._serialized_options = b'\302H\031\n\027\n\017fixed32.example\032\004true' + _globals['_FIXED64RULES'].fields_by_name['const']._loaded_options = None + _globals['_FIXED64RULES'].fields_by_name['const']._serialized_options = b'\302Hm\nk\n\rfixed64.const\032Zthis != getField(rules, \'const\') ? \'must equal %s\'.format([getField(rules, \'const\')]) : \'\'' + _globals['_FIXED64RULES'].fields_by_name['lt']._loaded_options = None + _globals['_FIXED64RULES'].fields_by_name['lt']._serialized_options = b'\302Hu\ns\n\nfixed64.lt\032e!has(rules.gte) && !has(rules.gt) && this >= rules.lt? \'must be less than %s\'.format([rules.lt]) : \'\'' + _globals['_FIXED64RULES'].fields_by_name['lte']._loaded_options = None + _globals['_FIXED64RULES'].fields_by_name['lte']._serialized_options = b'\302H\204\001\n\201\001\n\013fixed64.lte\032r!has(rules.gte) && !has(rules.gt) && this > rules.lte? \'must be less than or equal to %s\'.format([rules.lte]) : \'\'' + _globals['_FIXED64RULES'].fields_by_name['gt']._loaded_options = None + _globals['_FIXED64RULES'].fields_by_name['gt']._serialized_options = b'\302H\360\006\nv\n\nfixed64.gt\032h!has(rules.lt) && !has(rules.lte) && this <= rules.gt? \'must be greater than %s\'.format([rules.gt]) : \'\'\n\257\001\n\rfixed64.gt_lt\032\235\001has(rules.lt) && rules.lt >= rules.gt && (this >= rules.lt || this <= rules.gt)? \'must be greater than %s and less than %s\'.format([rules.gt, rules.lt]) : \'\'\n\267\001\n\027fixed64.gt_lt_exclusive\032\233\001has(rules.lt) && rules.lt < rules.gt && (rules.lt <= this && this <= rules.gt)? \'must be greater than %s or less than %s\'.format([rules.gt, rules.lt]) : \'\'\n\277\001\n\016fixed64.gt_lte\032\254\001has(rules.lte) && rules.lte >= rules.gt && (this > rules.lte || this <= rules.gt)? \'must be greater than %s and less than or equal to %s\'.format([rules.gt, rules.lte]) : \'\'\n\307\001\n\030fixed64.gt_lte_exclusive\032\252\001has(rules.lte) && rules.lte < rules.gt && (rules.lte < this && this <= rules.gt)? \'must be greater than %s or less than or equal to %s\'.format([rules.gt, rules.lte]) : \'\'' + _globals['_FIXED64RULES'].fields_by_name['gte']._loaded_options = None + _globals['_FIXED64RULES'].fields_by_name['gte']._serialized_options = b'\302H\273\007\n\204\001\n\013fixed64.gte\032u!has(rules.lt) && !has(rules.lte) && this < rules.gte? \'must be greater than or equal to %s\'.format([rules.gte]) : \'\'\n\276\001\n\016fixed64.gte_lt\032\253\001has(rules.lt) && rules.lt >= rules.gte && (this >= rules.lt || this < rules.gte)? \'must be greater than or equal to %s and less than %s\'.format([rules.gte, rules.lt]) : \'\'\n\306\001\n\030fixed64.gte_lt_exclusive\032\251\001has(rules.lt) && rules.lt < rules.gte && (rules.lt <= this && this < rules.gte)? \'must be greater than or equal to %s or less than %s\'.format([rules.gte, rules.lt]) : \'\'\n\316\001\n\017fixed64.gte_lte\032\272\001has(rules.lte) && rules.lte >= rules.gte && (this > rules.lte || this < rules.gte)? \'must be greater than or equal to %s and less than or equal to %s\'.format([rules.gte, rules.lte]) : \'\'\n\326\001\n\031fixed64.gte_lte_exclusive\032\270\001has(rules.lte) && rules.lte < rules.gte && (rules.lte < this && this < rules.gte)? \'must be greater than or equal to %s or less than or equal to %s\'.format([rules.gte, rules.lte]) : \'\'' + _globals['_FIXED64RULES'].fields_by_name['in']._loaded_options = None + _globals['_FIXED64RULES'].fields_by_name['in']._serialized_options = b'\302Hl\nj\n\nfixed64.in\032\\!(this in getField(rules, \'in\')) ? \'must be in list %s\'.format([getField(rules, \'in\')]) : \'\'' + _globals['_FIXED64RULES'].fields_by_name['not_in']._loaded_options = None + _globals['_FIXED64RULES'].fields_by_name['not_in']._serialized_options = b'\302H_\n]\n\016fixed64.not_in\032Kthis in rules.not_in ? \'must not be in list %s\'.format([rules.not_in]) : \'\'' + _globals['_FIXED64RULES'].fields_by_name['example']._loaded_options = None + _globals['_FIXED64RULES'].fields_by_name['example']._serialized_options = b'\302H\031\n\027\n\017fixed64.example\032\004true' + _globals['_SFIXED32RULES'].fields_by_name['const']._loaded_options = None + _globals['_SFIXED32RULES'].fields_by_name['const']._serialized_options = b'\302Hn\nl\n\016sfixed32.const\032Zthis != getField(rules, \'const\') ? \'must equal %s\'.format([getField(rules, \'const\')]) : \'\'' + _globals['_SFIXED32RULES'].fields_by_name['lt']._loaded_options = None + _globals['_SFIXED32RULES'].fields_by_name['lt']._serialized_options = b'\302Hv\nt\n\013sfixed32.lt\032e!has(rules.gte) && !has(rules.gt) && this >= rules.lt? \'must be less than %s\'.format([rules.lt]) : \'\'' + _globals['_SFIXED32RULES'].fields_by_name['lte']._loaded_options = None + _globals['_SFIXED32RULES'].fields_by_name['lte']._serialized_options = b'\302H\205\001\n\202\001\n\014sfixed32.lte\032r!has(rules.gte) && !has(rules.gt) && this > rules.lte? \'must be less than or equal to %s\'.format([rules.lte]) : \'\'' + _globals['_SFIXED32RULES'].fields_by_name['gt']._loaded_options = None + _globals['_SFIXED32RULES'].fields_by_name['gt']._serialized_options = b'\302H\365\006\nw\n\013sfixed32.gt\032h!has(rules.lt) && !has(rules.lte) && this <= rules.gt? \'must be greater than %s\'.format([rules.gt]) : \'\'\n\260\001\n\016sfixed32.gt_lt\032\235\001has(rules.lt) && rules.lt >= rules.gt && (this >= rules.lt || this <= rules.gt)? \'must be greater than %s and less than %s\'.format([rules.gt, rules.lt]) : \'\'\n\270\001\n\030sfixed32.gt_lt_exclusive\032\233\001has(rules.lt) && rules.lt < rules.gt && (rules.lt <= this && this <= rules.gt)? \'must be greater than %s or less than %s\'.format([rules.gt, rules.lt]) : \'\'\n\300\001\n\017sfixed32.gt_lte\032\254\001has(rules.lte) && rules.lte >= rules.gt && (this > rules.lte || this <= rules.gt)? \'must be greater than %s and less than or equal to %s\'.format([rules.gt, rules.lte]) : \'\'\n\310\001\n\031sfixed32.gt_lte_exclusive\032\252\001has(rules.lte) && rules.lte < rules.gt && (rules.lte < this && this <= rules.gt)? \'must be greater than %s or less than or equal to %s\'.format([rules.gt, rules.lte]) : \'\'' + _globals['_SFIXED32RULES'].fields_by_name['gte']._loaded_options = None + _globals['_SFIXED32RULES'].fields_by_name['gte']._serialized_options = b'\302H\300\007\n\205\001\n\014sfixed32.gte\032u!has(rules.lt) && !has(rules.lte) && this < rules.gte? \'must be greater than or equal to %s\'.format([rules.gte]) : \'\'\n\277\001\n\017sfixed32.gte_lt\032\253\001has(rules.lt) && rules.lt >= rules.gte && (this >= rules.lt || this < rules.gte)? \'must be greater than or equal to %s and less than %s\'.format([rules.gte, rules.lt]) : \'\'\n\307\001\n\031sfixed32.gte_lt_exclusive\032\251\001has(rules.lt) && rules.lt < rules.gte && (rules.lt <= this && this < rules.gte)? \'must be greater than or equal to %s or less than %s\'.format([rules.gte, rules.lt]) : \'\'\n\317\001\n\020sfixed32.gte_lte\032\272\001has(rules.lte) && rules.lte >= rules.gte && (this > rules.lte || this < rules.gte)? \'must be greater than or equal to %s and less than or equal to %s\'.format([rules.gte, rules.lte]) : \'\'\n\327\001\n\032sfixed32.gte_lte_exclusive\032\270\001has(rules.lte) && rules.lte < rules.gte && (rules.lte < this && this < rules.gte)? \'must be greater than or equal to %s or less than or equal to %s\'.format([rules.gte, rules.lte]) : \'\'' + _globals['_SFIXED32RULES'].fields_by_name['in']._loaded_options = None + _globals['_SFIXED32RULES'].fields_by_name['in']._serialized_options = b'\302Hm\nk\n\013sfixed32.in\032\\!(this in getField(rules, \'in\')) ? \'must be in list %s\'.format([getField(rules, \'in\')]) : \'\'' + _globals['_SFIXED32RULES'].fields_by_name['not_in']._loaded_options = None + _globals['_SFIXED32RULES'].fields_by_name['not_in']._serialized_options = b'\302H`\n^\n\017sfixed32.not_in\032Kthis in rules.not_in ? \'must not be in list %s\'.format([rules.not_in]) : \'\'' + _globals['_SFIXED32RULES'].fields_by_name['example']._loaded_options = None + _globals['_SFIXED32RULES'].fields_by_name['example']._serialized_options = b'\302H\032\n\030\n\020sfixed32.example\032\004true' + _globals['_SFIXED64RULES'].fields_by_name['const']._loaded_options = None + _globals['_SFIXED64RULES'].fields_by_name['const']._serialized_options = b'\302Hn\nl\n\016sfixed64.const\032Zthis != getField(rules, \'const\') ? \'must equal %s\'.format([getField(rules, \'const\')]) : \'\'' + _globals['_SFIXED64RULES'].fields_by_name['lt']._loaded_options = None + _globals['_SFIXED64RULES'].fields_by_name['lt']._serialized_options = b'\302Hv\nt\n\013sfixed64.lt\032e!has(rules.gte) && !has(rules.gt) && this >= rules.lt? \'must be less than %s\'.format([rules.lt]) : \'\'' + _globals['_SFIXED64RULES'].fields_by_name['lte']._loaded_options = None + _globals['_SFIXED64RULES'].fields_by_name['lte']._serialized_options = b'\302H\205\001\n\202\001\n\014sfixed64.lte\032r!has(rules.gte) && !has(rules.gt) && this > rules.lte? \'must be less than or equal to %s\'.format([rules.lte]) : \'\'' + _globals['_SFIXED64RULES'].fields_by_name['gt']._loaded_options = None + _globals['_SFIXED64RULES'].fields_by_name['gt']._serialized_options = b'\302H\365\006\nw\n\013sfixed64.gt\032h!has(rules.lt) && !has(rules.lte) && this <= rules.gt? \'must be greater than %s\'.format([rules.gt]) : \'\'\n\260\001\n\016sfixed64.gt_lt\032\235\001has(rules.lt) && rules.lt >= rules.gt && (this >= rules.lt || this <= rules.gt)? \'must be greater than %s and less than %s\'.format([rules.gt, rules.lt]) : \'\'\n\270\001\n\030sfixed64.gt_lt_exclusive\032\233\001has(rules.lt) && rules.lt < rules.gt && (rules.lt <= this && this <= rules.gt)? \'must be greater than %s or less than %s\'.format([rules.gt, rules.lt]) : \'\'\n\300\001\n\017sfixed64.gt_lte\032\254\001has(rules.lte) && rules.lte >= rules.gt && (this > rules.lte || this <= rules.gt)? \'must be greater than %s and less than or equal to %s\'.format([rules.gt, rules.lte]) : \'\'\n\310\001\n\031sfixed64.gt_lte_exclusive\032\252\001has(rules.lte) && rules.lte < rules.gt && (rules.lte < this && this <= rules.gt)? \'must be greater than %s or less than or equal to %s\'.format([rules.gt, rules.lte]) : \'\'' + _globals['_SFIXED64RULES'].fields_by_name['gte']._loaded_options = None + _globals['_SFIXED64RULES'].fields_by_name['gte']._serialized_options = b'\302H\300\007\n\205\001\n\014sfixed64.gte\032u!has(rules.lt) && !has(rules.lte) && this < rules.gte? \'must be greater than or equal to %s\'.format([rules.gte]) : \'\'\n\277\001\n\017sfixed64.gte_lt\032\253\001has(rules.lt) && rules.lt >= rules.gte && (this >= rules.lt || this < rules.gte)? \'must be greater than or equal to %s and less than %s\'.format([rules.gte, rules.lt]) : \'\'\n\307\001\n\031sfixed64.gte_lt_exclusive\032\251\001has(rules.lt) && rules.lt < rules.gte && (rules.lt <= this && this < rules.gte)? \'must be greater than or equal to %s or less than %s\'.format([rules.gte, rules.lt]) : \'\'\n\317\001\n\020sfixed64.gte_lte\032\272\001has(rules.lte) && rules.lte >= rules.gte && (this > rules.lte || this < rules.gte)? \'must be greater than or equal to %s and less than or equal to %s\'.format([rules.gte, rules.lte]) : \'\'\n\327\001\n\032sfixed64.gte_lte_exclusive\032\270\001has(rules.lte) && rules.lte < rules.gte && (rules.lte < this && this < rules.gte)? \'must be greater than or equal to %s or less than or equal to %s\'.format([rules.gte, rules.lte]) : \'\'' + _globals['_SFIXED64RULES'].fields_by_name['in']._loaded_options = None + _globals['_SFIXED64RULES'].fields_by_name['in']._serialized_options = b'\302Hm\nk\n\013sfixed64.in\032\\!(this in getField(rules, \'in\')) ? \'must be in list %s\'.format([getField(rules, \'in\')]) : \'\'' + _globals['_SFIXED64RULES'].fields_by_name['not_in']._loaded_options = None + _globals['_SFIXED64RULES'].fields_by_name['not_in']._serialized_options = b'\302H`\n^\n\017sfixed64.not_in\032Kthis in rules.not_in ? \'must not be in list %s\'.format([rules.not_in]) : \'\'' + _globals['_SFIXED64RULES'].fields_by_name['example']._loaded_options = None + _globals['_SFIXED64RULES'].fields_by_name['example']._serialized_options = b'\302H\032\n\030\n\020sfixed64.example\032\004true' + _globals['_BOOLRULES'].fields_by_name['const']._loaded_options = None + _globals['_BOOLRULES'].fields_by_name['const']._serialized_options = b'\302Hj\nh\n\nbool.const\032Zthis != getField(rules, \'const\') ? \'must equal %s\'.format([getField(rules, \'const\')]) : \'\'' + _globals['_BOOLRULES'].fields_by_name['example']._loaded_options = None + _globals['_BOOLRULES'].fields_by_name['example']._serialized_options = b'\302H\026\n\024\n\014bool.example\032\004true' + _globals['_STRINGRULES'].fields_by_name['const']._loaded_options = None + _globals['_STRINGRULES'].fields_by_name['const']._serialized_options = b'\302Hn\nl\n\014string.const\032\\this != getField(rules, \'const\') ? \'must equal `%s`\'.format([getField(rules, \'const\')]) : \'\'' + _globals['_STRINGRULES'].fields_by_name['len']._loaded_options = None + _globals['_STRINGRULES'].fields_by_name['len']._serialized_options = b'\302Ha\n_\n\nstring.len\032Quint(this.size()) != rules.len ? \'must be %s characters\'.format([rules.len]) : \'\'' + _globals['_STRINGRULES'].fields_by_name['min_len']._loaded_options = None + _globals['_STRINGRULES'].fields_by_name['min_len']._serialized_options = b'\302Hu\ns\n\016string.min_len\032auint(this.size()) < rules.min_len ? \'must be at least %s characters\'.format([rules.min_len]) : \'\'' + _globals['_STRINGRULES'].fields_by_name['max_len']._loaded_options = None + _globals['_STRINGRULES'].fields_by_name['max_len']._serialized_options = b'\302Ht\nr\n\016string.max_len\032`uint(this.size()) > rules.max_len ? \'must be at most %s characters\'.format([rules.max_len]) : \'\'' + _globals['_STRINGRULES'].fields_by_name['len_bytes']._loaded_options = None + _globals['_STRINGRULES'].fields_by_name['len_bytes']._serialized_options = b'\302Hu\ns\n\020string.len_bytes\032_uint(bytes(this).size()) != rules.len_bytes ? \'must be %s bytes\'.format([rules.len_bytes]) : \'\'' + _globals['_STRINGRULES'].fields_by_name['min_bytes']._loaded_options = None + _globals['_STRINGRULES'].fields_by_name['min_bytes']._serialized_options = b'\302H}\n{\n\020string.min_bytes\032guint(bytes(this).size()) < rules.min_bytes ? \'must be at least %s bytes\'.format([rules.min_bytes]) : \'\'' + _globals['_STRINGRULES'].fields_by_name['max_bytes']._loaded_options = None + _globals['_STRINGRULES'].fields_by_name['max_bytes']._serialized_options = b'\302H|\nz\n\020string.max_bytes\032fuint(bytes(this).size()) > rules.max_bytes ? \'must be at most %s bytes\'.format([rules.max_bytes]) : \'\'' + _globals['_STRINGRULES'].fields_by_name['pattern']._loaded_options = None + _globals['_STRINGRULES'].fields_by_name['pattern']._serialized_options = b'\302Hs\nq\n\016string.pattern\032_!this.matches(rules.pattern) ? \'does not match regex pattern `%s`\'.format([rules.pattern]) : \'\'' + _globals['_STRINGRULES'].fields_by_name['prefix']._loaded_options = None + _globals['_STRINGRULES'].fields_by_name['prefix']._serialized_options = b'\302Hk\ni\n\rstring.prefix\032X!this.startsWith(rules.prefix) ? \'does not have prefix `%s`\'.format([rules.prefix]) : \'\'' + _globals['_STRINGRULES'].fields_by_name['suffix']._loaded_options = None + _globals['_STRINGRULES'].fields_by_name['suffix']._serialized_options = b'\302Hi\ng\n\rstring.suffix\032V!this.endsWith(rules.suffix) ? \'does not have suffix `%s`\'.format([rules.suffix]) : \'\'' + _globals['_STRINGRULES'].fields_by_name['contains']._loaded_options = None + _globals['_STRINGRULES'].fields_by_name['contains']._serialized_options = b'\302Hu\ns\n\017string.contains\032`!this.contains(rules.contains) ? \'does not contain substring `%s`\'.format([rules.contains]) : \'\'' + _globals['_STRINGRULES'].fields_by_name['not_contains']._loaded_options = None + _globals['_STRINGRULES'].fields_by_name['not_contains']._serialized_options = b'\302Hx\nv\n\023string.not_contains\032_this.contains(rules.not_contains) ? \'contains substring `%s`\'.format([rules.not_contains]) : \'\'' + _globals['_STRINGRULES'].fields_by_name['in']._loaded_options = None + _globals['_STRINGRULES'].fields_by_name['in']._serialized_options = b'\302Hk\ni\n\tstring.in\032\\!(this in getField(rules, \'in\')) ? \'must be in list %s\'.format([getField(rules, \'in\')]) : \'\'' + _globals['_STRINGRULES'].fields_by_name['not_in']._loaded_options = None + _globals['_STRINGRULES'].fields_by_name['not_in']._serialized_options = b'\302H^\n\\\n\rstring.not_in\032Kthis in rules.not_in ? \'must not be in list %s\'.format([rules.not_in]) : \'\'' + _globals['_STRINGRULES'].fields_by_name['email']._loaded_options = None + _globals['_STRINGRULES'].fields_by_name['email']._serialized_options = b'\302H\303\001\n[\n\014string.email\022\035must be a valid email address\032,!rules.email || this == \'\' || this.isEmail()\nd\n\022string.email_empty\0222value is empty, which is not a valid email address\032\032!rules.email || this != \'\'' + _globals['_STRINGRULES'].fields_by_name['hostname']._loaded_options = None + _globals['_STRINGRULES'].fields_by_name['hostname']._serialized_options = b'\302H\310\001\n_\n\017string.hostname\022\030must be a valid hostname\0322!rules.hostname || this == \'\' || this.isHostname()\ne\n\025string.hostname_empty\022-value is empty, which is not a valid hostname\032\035!rules.hostname || this != \'\'' + _globals['_STRINGRULES'].fields_by_name['ip']._loaded_options = None + _globals['_STRINGRULES'].fields_by_name['ip']._serialized_options = b'\302H\256\001\nO\n\tstring.ip\022\032must be a valid IP address\032&!rules.ip || this == \'\' || this.isIp()\n[\n\017string.ip_empty\022/value is empty, which is not a valid IP address\032\027!rules.ip || this != \'\'' + _globals['_STRINGRULES'].fields_by_name['ipv4']._loaded_options = None + _globals['_STRINGRULES'].fields_by_name['ipv4']._serialized_options = b'\302H\273\001\nV\n\013string.ipv4\022\034must be a valid IPv4 address\032)!rules.ipv4 || this == \'\' || this.isIp(4)\na\n\021string.ipv4_empty\0221value is empty, which is not a valid IPv4 address\032\031!rules.ipv4 || this != \'\'' + _globals['_STRINGRULES'].fields_by_name['ipv6']._loaded_options = None + _globals['_STRINGRULES'].fields_by_name['ipv6']._serialized_options = b'\302H\273\001\nV\n\013string.ipv6\022\034must be a valid IPv6 address\032)!rules.ipv6 || this == \'\' || this.isIp(6)\na\n\021string.ipv6_empty\0221value is empty, which is not a valid IPv6 address\032\031!rules.ipv6 || this != \'\'' + _globals['_STRINGRULES'].fields_by_name['uri']._loaded_options = None + _globals['_STRINGRULES'].fields_by_name['uri']._serialized_options = b'\302H\245\001\nK\n\nstring.uri\022\023must be a valid URI\032(!rules.uri || this == \'\' || this.isUri()\nV\n\020string.uri_empty\022(value is empty, which is not a valid URI\032\030!rules.uri || this != \'\'' + _globals['_STRINGRULES'].fields_by_name['uri_ref']._loaded_options = None + _globals['_STRINGRULES'].fields_by_name['uri_ref']._serialized_options = b'\302HT\nR\n\016string.uri_ref\022\035must be a valid URI Reference\032!!rules.uri_ref || this.isUriRef()' + _globals['_STRINGRULES'].fields_by_name['address']._loaded_options = None + _globals['_STRINGRULES'].fields_by_name['address']._serialized_options = b'\302H\361\001\n{\n\016string.address\022\'must be a valid hostname, or ip address\032@!rules.address || this == \'\' || this.isHostname() || this.isIp()\nr\n\024string.address_empty\022!rules.ipv4_with_prefixlen || this == \'\' || this.isIpPrefix(4)\n\222\001\n string.ipv4_with_prefixlen_empty\022Dvalue is empty, which is not a valid IPv4 address with prefix length\032(!rules.ipv4_with_prefixlen || this != \'\'' + _globals['_STRINGRULES'].fields_by_name['ipv6_with_prefixlen']._loaded_options = None + _globals['_STRINGRULES'].fields_by_name['ipv6_with_prefixlen']._serialized_options = b'\302H\245\002\n\215\001\n\032string.ipv6_with_prefixlen\022/must be a valid IPv6 address with prefix length\032>!rules.ipv6_with_prefixlen || this == \'\' || this.isIpPrefix(6)\n\222\001\n string.ipv6_with_prefixlen_empty\022Dvalue is empty, which is not a valid IPv6 address with prefix length\032(!rules.ipv6_with_prefixlen || this != \'\'' + _globals['_STRINGRULES'].fields_by_name['ip_prefix']._loaded_options = None + _globals['_STRINGRULES'].fields_by_name['ip_prefix']._serialized_options = b'\302H\322\001\nf\n\020string.ip_prefix\022\031must be a valid IP prefix\0327!rules.ip_prefix || this == \'\' || this.isIpPrefix(true)\nh\n\026string.ip_prefix_empty\022.value is empty, which is not a valid IP prefix\032\036!rules.ip_prefix || this != \'\'' + _globals['_STRINGRULES'].fields_by_name['ipv4_prefix']._loaded_options = None + _globals['_STRINGRULES'].fields_by_name['ipv4_prefix']._serialized_options = b'\302H\341\001\no\n\022string.ipv4_prefix\022\033must be a valid IPv4 prefix\032!rules.host_and_port || this == \'\' || this.isHostAndPort(true)\ny\n\032string.host_and_port_empty\0227value is empty, which is not a valid host and port pair\032\"!rules.host_and_port || this != \'\'' + _globals['_STRINGRULES'].fields_by_name['ulid']._loaded_options = None + _globals['_STRINGRULES'].fields_by_name['ulid']._serialized_options = b'\302H\331\001\n|\n\013string.ulid\022\024must be a valid ULID\032W!rules.ulid || this == \'\' || this.matches(\'^[0-7][0-9A-HJKMNP-TV-Za-hjkmnp-tv-z]{25}$\')\nY\n\021string.ulid_empty\022)value is empty, which is not a valid ULID\032\031!rules.ulid || this != \'\'' + _globals['_STRINGRULES'].fields_by_name['protobuf_fqn']._loaded_options = None + _globals['_STRINGRULES'].fields_by_name['protobuf_fqn']._serialized_options = b'\302H\267\002\n\257\001\n\023string.protobuf_fqn\022-must be a valid fully-qualified Protobuf name\032i!rules.protobuf_fqn || this == \'\' || this.matches(\'^[A-Za-z_][A-Za-z_0-9]*(\\\\.[A-Za-z_][A-Za-z_0-9]*)*$\')\n\202\001\n\031string.protobuf_fqn_empty\022Bvalue is empty, which is not a valid fully-qualified Protobuf name\032!!rules.protobuf_fqn || this != \'\'' + _globals['_STRINGRULES'].fields_by_name['protobuf_dot_fqn']._loaded_options = None + _globals['_STRINGRULES'].fields_by_name['protobuf_dot_fqn']._serialized_options = b'\302H\360\002\n\315\001\n\027string.protobuf_dot_fqn\022@must be a valid fully-qualified Protobuf name with a leading dot\032p!rules.protobuf_dot_fqn || this == \'\' || this.matches(\'^\\\\.[A-Za-z_][A-Za-z_0-9]*(\\\\.[A-Za-z_][A-Za-z_0-9]*)*$\')\n\235\001\n\035string.protobuf_dot_fqn_empty\022Uvalue is empty, which is not a valid fully-qualified Protobuf name with a leading dot\032%!rules.protobuf_dot_fqn || this != \'\'' + _globals['_STRINGRULES'].fields_by_name['well_known_regex']._loaded_options = None + _globals['_STRINGRULES'].fields_by_name['well_known_regex']._serialized_options = b'\302H\341\004\n\352\001\n#string.well_known_regex.header_name\022 must be a valid HTTP header name\032\240\001rules.well_known_regex != 1 || this == \'\' || this.matches(!has(rules.strict) || rules.strict ?\'^:?[0-9a-zA-Z!#$%&\\\'*+-.^_|~\\x60]+$\' :\'^[^\\u0000\\u000A\\u000D]+$\')\n\215\001\n)string.well_known_regex.header_name_empty\0225value is empty, which is not a valid HTTP header name\032)rules.well_known_regex != 1 || this != \'\'\n\341\001\n$string.well_known_regex.header_value\022!must be a valid HTTP header value\032\225\001rules.well_known_regex != 2 || this.matches(!has(rules.strict) || rules.strict ?\'^[^\\u0000-\\u0008\\u000A-\\u001F\\u007F]*$\' :\'^[^\\u0000\\u000A\\u000D]*$\')' + _globals['_STRINGRULES'].fields_by_name['example']._loaded_options = None + _globals['_STRINGRULES'].fields_by_name['example']._serialized_options = b'\302H\030\n\026\n\016string.example\032\004true' + _globals['_BYTESRULES'].fields_by_name['const']._loaded_options = None + _globals['_BYTESRULES'].fields_by_name['const']._serialized_options = b'\302Hh\nf\n\013bytes.const\032Wthis != getField(rules, \'const\') ? \'must be %x\'.format([getField(rules, \'const\')]) : \'\'' + _globals['_BYTESRULES'].fields_by_name['len']._loaded_options = None + _globals['_BYTESRULES'].fields_by_name['len']._serialized_options = b'\302H[\nY\n\tbytes.len\032Luint(this.size()) != rules.len ? \'must be %s bytes\'.format([rules.len]) : \'\'' + _globals['_BYTESRULES'].fields_by_name['min_len']._loaded_options = None + _globals['_BYTESRULES'].fields_by_name['min_len']._serialized_options = b'\302Ho\nm\n\rbytes.min_len\032\\uint(this.size()) < rules.min_len ? \'must be at least %s bytes\'.format([rules.min_len]) : \'\'' + _globals['_BYTESRULES'].fields_by_name['max_len']._loaded_options = None + _globals['_BYTESRULES'].fields_by_name['max_len']._serialized_options = b'\302Hn\nl\n\rbytes.max_len\032[uint(this.size()) > rules.max_len ? \'must be at most %s bytes\'.format([rules.max_len]) : \'\'' + _globals['_BYTESRULES'].fields_by_name['pattern']._loaded_options = None + _globals['_BYTESRULES'].fields_by_name['pattern']._serialized_options = b'\302Hv\nt\n\rbytes.pattern\032c!string(this).matches(rules.pattern) ? \'must match regex pattern `%s`\'.format([rules.pattern]) : \'\'' + _globals['_BYTESRULES'].fields_by_name['prefix']._loaded_options = None + _globals['_BYTESRULES'].fields_by_name['prefix']._serialized_options = b'\302Hh\nf\n\014bytes.prefix\032V!this.startsWith(rules.prefix) ? \'does not have prefix %x\'.format([rules.prefix]) : \'\'' + _globals['_BYTESRULES'].fields_by_name['suffix']._loaded_options = None + _globals['_BYTESRULES'].fields_by_name['suffix']._serialized_options = b'\302Hf\nd\n\014bytes.suffix\032T!this.endsWith(rules.suffix) ? \'does not have suffix %x\'.format([rules.suffix]) : \'\'' + _globals['_BYTESRULES'].fields_by_name['contains']._loaded_options = None + _globals['_BYTESRULES'].fields_by_name['contains']._serialized_options = b'\302Hh\nf\n\016bytes.contains\032T!this.contains(rules.contains) ? \'does not contain %x\'.format([rules.contains]) : \'\'' + _globals['_BYTESRULES'].fields_by_name['in']._loaded_options = None + _globals['_BYTESRULES'].fields_by_name['in']._serialized_options = b'\302H\220\001\n\215\001\n\010bytes.in\032\200\001getField(rules, \'in\').size() > 0 && !(this in getField(rules, \'in\')) ? \'must be in list %s\'.format([getField(rules, \'in\')]) : \'\'' + _globals['_BYTESRULES'].fields_by_name['not_in']._loaded_options = None + _globals['_BYTESRULES'].fields_by_name['not_in']._serialized_options = b'\302H]\n[\n\014bytes.not_in\032Kthis in rules.not_in ? \'must not be in list %s\'.format([rules.not_in]) : \'\'' + _globals['_BYTESRULES'].fields_by_name['ip']._loaded_options = None + _globals['_BYTESRULES'].fields_by_name['ip']._serialized_options = b'\302H\322\001\nn\n\010bytes.ip\022\032must be a valid IP address\032F!rules.ip || this.size() == 0 || this.size() == 4 || this.size() == 16\n`\n\016bytes.ip_empty\022/value is empty, which is not a valid IP address\032\035!rules.ip || this.size() != 0' + _globals['_BYTESRULES'].fields_by_name['ipv4']._loaded_options = None + _globals['_BYTESRULES'].fields_by_name['ipv4']._serialized_options = b'\302H\311\001\n_\n\nbytes.ipv4\022\034must be a valid IPv4 address\0323!rules.ipv4 || this.size() == 0 || this.size() == 4\nf\n\020bytes.ipv4_empty\0221value is empty, which is not a valid IPv4 address\032\037!rules.ipv4 || this.size() != 0' + _globals['_BYTESRULES'].fields_by_name['ipv6']._loaded_options = None + _globals['_BYTESRULES'].fields_by_name['ipv6']._serialized_options = b'\302H\312\001\n`\n\nbytes.ipv6\022\034must be a valid IPv6 address\0324!rules.ipv6 || this.size() == 0 || this.size() == 16\nf\n\020bytes.ipv6_empty\0221value is empty, which is not a valid IPv6 address\032\037!rules.ipv6 || this.size() != 0' + _globals['_BYTESRULES'].fields_by_name['uuid']._loaded_options = None + _globals['_BYTESRULES'].fields_by_name['uuid']._serialized_options = b'\302H\272\001\nX\n\nbytes.uuid\022\024must be a valid UUID\0324!rules.uuid || this.size() == 0 || this.size() == 16\n^\n\020bytes.uuid_empty\022)value is empty, which is not a valid UUID\032\037!rules.uuid || this.size() != 0' + _globals['_BYTESRULES'].fields_by_name['example']._loaded_options = None + _globals['_BYTESRULES'].fields_by_name['example']._serialized_options = b'\302H\027\n\025\n\rbytes.example\032\004true' + _globals['_ENUMRULES'].fields_by_name['const']._loaded_options = None + _globals['_ENUMRULES'].fields_by_name['const']._serialized_options = b'\302Hj\nh\n\nenum.const\032Zthis != getField(rules, \'const\') ? \'must equal %s\'.format([getField(rules, \'const\')]) : \'\'' + _globals['_ENUMRULES'].fields_by_name['in']._loaded_options = None + _globals['_ENUMRULES'].fields_by_name['in']._serialized_options = b'\302Hi\ng\n\007enum.in\032\\!(this in getField(rules, \'in\')) ? \'must be in list %s\'.format([getField(rules, \'in\')]) : \'\'' + _globals['_ENUMRULES'].fields_by_name['not_in']._loaded_options = None + _globals['_ENUMRULES'].fields_by_name['not_in']._serialized_options = b'\302H\\\nZ\n\013enum.not_in\032Kthis in rules.not_in ? \'must not be in list %s\'.format([rules.not_in]) : \'\'' + _globals['_ENUMRULES'].fields_by_name['example']._loaded_options = None + _globals['_ENUMRULES'].fields_by_name['example']._serialized_options = b'\302H\026\n\024\n\014enum.example\032\004true' + _globals['_REPEATEDRULES'].fields_by_name['min_items']._loaded_options = None + _globals['_REPEATEDRULES'].fields_by_name['min_items']._serialized_options = b'\302H\177\n}\n\022repeated.min_items\032guint(this.size()) < rules.min_items ? \'must contain at least %d item(s)\'.format([rules.min_items]) : \'\'' + _globals['_REPEATEDRULES'].fields_by_name['max_items']._loaded_options = None + _globals['_REPEATEDRULES'].fields_by_name['max_items']._serialized_options = b'\302H\204\001\n\201\001\n\022repeated.max_items\032kuint(this.size()) > rules.max_items ? \'must contain no more than %s item(s)\'.format([rules.max_items]) : \'\'' + _globals['_REPEATEDRULES'].fields_by_name['unique']._loaded_options = None + _globals['_REPEATEDRULES'].fields_by_name['unique']._serialized_options = b'\302H]\n[\n\017repeated.unique\022(repeated value must contain unique items\032\036!rules.unique || this.unique()' + _globals['_MAPRULES'].fields_by_name['min_pairs']._loaded_options = None + _globals['_MAPRULES'].fields_by_name['min_pairs']._serialized_options = b'\302Hy\nw\n\rmap.min_pairs\032fuint(this.size()) < rules.min_pairs ? \'map must be at least %d entries\'.format([rules.min_pairs]) : \'\'' + _globals['_MAPRULES'].fields_by_name['max_pairs']._loaded_options = None + _globals['_MAPRULES'].fields_by_name['max_pairs']._serialized_options = b'\302Hx\nv\n\rmap.max_pairs\032euint(this.size()) > rules.max_pairs ? \'map must be at most %d entries\'.format([rules.max_pairs]) : \'\'' + _globals['_DURATIONRULES'].fields_by_name['const']._loaded_options = None + _globals['_DURATIONRULES'].fields_by_name['const']._serialized_options = b'\302Hn\nl\n\016duration.const\032Zthis != getField(rules, \'const\') ? \'must equal %s\'.format([getField(rules, \'const\')]) : \'\'' + _globals['_DURATIONRULES'].fields_by_name['lt']._loaded_options = None + _globals['_DURATIONRULES'].fields_by_name['lt']._serialized_options = b'\302Hv\nt\n\013duration.lt\032e!has(rules.gte) && !has(rules.gt) && this >= rules.lt? \'must be less than %s\'.format([rules.lt]) : \'\'' + _globals['_DURATIONRULES'].fields_by_name['lte']._loaded_options = None + _globals['_DURATIONRULES'].fields_by_name['lte']._serialized_options = b'\302H\205\001\n\202\001\n\014duration.lte\032r!has(rules.gte) && !has(rules.gt) && this > rules.lte? \'must be less than or equal to %s\'.format([rules.lte]) : \'\'' + _globals['_DURATIONRULES'].fields_by_name['gt']._loaded_options = None + _globals['_DURATIONRULES'].fields_by_name['gt']._serialized_options = b'\302H\365\006\nw\n\013duration.gt\032h!has(rules.lt) && !has(rules.lte) && this <= rules.gt? \'must be greater than %s\'.format([rules.gt]) : \'\'\n\260\001\n\016duration.gt_lt\032\235\001has(rules.lt) && rules.lt >= rules.gt && (this >= rules.lt || this <= rules.gt)? \'must be greater than %s and less than %s\'.format([rules.gt, rules.lt]) : \'\'\n\270\001\n\030duration.gt_lt_exclusive\032\233\001has(rules.lt) && rules.lt < rules.gt && (rules.lt <= this && this <= rules.gt)? \'must be greater than %s or less than %s\'.format([rules.gt, rules.lt]) : \'\'\n\300\001\n\017duration.gt_lte\032\254\001has(rules.lte) && rules.lte >= rules.gt && (this > rules.lte || this <= rules.gt)? \'must be greater than %s and less than or equal to %s\'.format([rules.gt, rules.lte]) : \'\'\n\310\001\n\031duration.gt_lte_exclusive\032\252\001has(rules.lte) && rules.lte < rules.gt && (rules.lte < this && this <= rules.gt)? \'must be greater than %s or less than or equal to %s\'.format([rules.gt, rules.lte]) : \'\'' + _globals['_DURATIONRULES'].fields_by_name['gte']._loaded_options = None + _globals['_DURATIONRULES'].fields_by_name['gte']._serialized_options = b'\302H\300\007\n\205\001\n\014duration.gte\032u!has(rules.lt) && !has(rules.lte) && this < rules.gte? \'must be greater than or equal to %s\'.format([rules.gte]) : \'\'\n\277\001\n\017duration.gte_lt\032\253\001has(rules.lt) && rules.lt >= rules.gte && (this >= rules.lt || this < rules.gte)? \'must be greater than or equal to %s and less than %s\'.format([rules.gte, rules.lt]) : \'\'\n\307\001\n\031duration.gte_lt_exclusive\032\251\001has(rules.lt) && rules.lt < rules.gte && (rules.lt <= this && this < rules.gte)? \'must be greater than or equal to %s or less than %s\'.format([rules.gte, rules.lt]) : \'\'\n\317\001\n\020duration.gte_lte\032\272\001has(rules.lte) && rules.lte >= rules.gte && (this > rules.lte || this < rules.gte)? \'must be greater than or equal to %s and less than or equal to %s\'.format([rules.gte, rules.lte]) : \'\'\n\327\001\n\032duration.gte_lte_exclusive\032\270\001has(rules.lte) && rules.lte < rules.gte && (rules.lte < this && this < rules.gte)? \'must be greater than or equal to %s or less than or equal to %s\'.format([rules.gte, rules.lte]) : \'\'' + _globals['_DURATIONRULES'].fields_by_name['in']._loaded_options = None + _globals['_DURATIONRULES'].fields_by_name['in']._serialized_options = b'\302Hm\nk\n\013duration.in\032\\!(this in getField(rules, \'in\')) ? \'must be in list %s\'.format([getField(rules, \'in\')]) : \'\'' + _globals['_DURATIONRULES'].fields_by_name['not_in']._loaded_options = None + _globals['_DURATIONRULES'].fields_by_name['not_in']._serialized_options = b'\302H`\n^\n\017duration.not_in\032Kthis in rules.not_in ? \'must not be in list %s\'.format([rules.not_in]) : \'\'' + _globals['_DURATIONRULES'].fields_by_name['example']._loaded_options = None + _globals['_DURATIONRULES'].fields_by_name['example']._serialized_options = b'\302H\032\n\030\n\020duration.example\032\004true' + _globals['_FIELDMASKRULES'].fields_by_name['const']._loaded_options = None + _globals['_FIELDMASKRULES'].fields_by_name['const']._serialized_options = b'\302H\211\001\n\206\001\n\020field_mask.const\032rthis.paths != getField(rules, \'const\').paths ? \'must equal paths %s\'.format([getField(rules, \'const\').paths]) : \'\'' + _globals['_FIELDMASKRULES'].fields_by_name['in']._loaded_options = None + _globals['_FIELDMASKRULES'].fields_by_name['in']._serialized_options = b'\302H\302\001\n\277\001\n\rfield_mask.in\032\255\001!this.paths.all(p, p in getField(rules, \'in\') || getField(rules, \'in\').exists(f, p.startsWith(f+\'.\'))) ? \'must only contain paths in %s\'.format([getField(rules, \'in\')]) : \'\'' + _globals['_FIELDMASKRULES'].fields_by_name['not_in']._loaded_options = None + _globals['_FIELDMASKRULES'].fields_by_name['not_in']._serialized_options = b'\302H\330\001\n\325\001\n\021field_mask.not_in\032\277\001!this.paths.all(p, !(p in getField(rules, \'not_in\') || getField(rules, \'not_in\').exists(f, p.startsWith(f+\'.\')))) ? \'must not contain any paths in %s\'.format([getField(rules, \'not_in\')]) : \'\'' + _globals['_FIELDMASKRULES'].fields_by_name['example']._loaded_options = None + _globals['_FIELDMASKRULES'].fields_by_name['example']._serialized_options = b'\302H\034\n\032\n\022field_mask.example\032\004true' + _globals['_TIMESTAMPRULES'].fields_by_name['const']._loaded_options = None + _globals['_TIMESTAMPRULES'].fields_by_name['const']._serialized_options = b'\302Ho\nm\n\017timestamp.const\032Zthis != getField(rules, \'const\') ? \'must equal %s\'.format([getField(rules, \'const\')]) : \'\'' + _globals['_TIMESTAMPRULES'].fields_by_name['lt']._loaded_options = None + _globals['_TIMESTAMPRULES'].fields_by_name['lt']._serialized_options = b'\302Hw\nu\n\014timestamp.lt\032e!has(rules.gte) && !has(rules.gt) && this >= rules.lt? \'must be less than %s\'.format([rules.lt]) : \'\'' + _globals['_TIMESTAMPRULES'].fields_by_name['lte']._loaded_options = None + _globals['_TIMESTAMPRULES'].fields_by_name['lte']._serialized_options = b'\302H\206\001\n\203\001\n\rtimestamp.lte\032r!has(rules.gte) && !has(rules.gt) && this > rules.lte? \'must be less than or equal to %s\'.format([rules.lte]) : \'\'' + _globals['_TIMESTAMPRULES'].fields_by_name['lt_now']._loaded_options = None + _globals['_TIMESTAMPRULES'].fields_by_name['lt_now']._serialized_options = b'\302HQ\nO\n\020timestamp.lt_now\032;(rules.lt_now && this > now) ? \'must be less than now\' : \'\'' + _globals['_TIMESTAMPRULES'].fields_by_name['gt']._loaded_options = None + _globals['_TIMESTAMPRULES'].fields_by_name['gt']._serialized_options = b'\302H\372\006\nx\n\014timestamp.gt\032h!has(rules.lt) && !has(rules.lte) && this <= rules.gt? \'must be greater than %s\'.format([rules.gt]) : \'\'\n\261\001\n\017timestamp.gt_lt\032\235\001has(rules.lt) && rules.lt >= rules.gt && (this >= rules.lt || this <= rules.gt)? \'must be greater than %s and less than %s\'.format([rules.gt, rules.lt]) : \'\'\n\271\001\n\031timestamp.gt_lt_exclusive\032\233\001has(rules.lt) && rules.lt < rules.gt && (rules.lt <= this && this <= rules.gt)? \'must be greater than %s or less than %s\'.format([rules.gt, rules.lt]) : \'\'\n\301\001\n\020timestamp.gt_lte\032\254\001has(rules.lte) && rules.lte >= rules.gt && (this > rules.lte || this <= rules.gt)? \'must be greater than %s and less than or equal to %s\'.format([rules.gt, rules.lte]) : \'\'\n\311\001\n\032timestamp.gt_lte_exclusive\032\252\001has(rules.lte) && rules.lte < rules.gt && (rules.lte < this && this <= rules.gt)? \'must be greater than %s or less than or equal to %s\'.format([rules.gt, rules.lte]) : \'\'' + _globals['_TIMESTAMPRULES'].fields_by_name['gte']._loaded_options = None + _globals['_TIMESTAMPRULES'].fields_by_name['gte']._serialized_options = b'\302H\305\007\n\206\001\n\rtimestamp.gte\032u!has(rules.lt) && !has(rules.lte) && this < rules.gte? \'must be greater than or equal to %s\'.format([rules.gte]) : \'\'\n\300\001\n\020timestamp.gte_lt\032\253\001has(rules.lt) && rules.lt >= rules.gte && (this >= rules.lt || this < rules.gte)? \'must be greater than or equal to %s and less than %s\'.format([rules.gte, rules.lt]) : \'\'\n\310\001\n\032timestamp.gte_lt_exclusive\032\251\001has(rules.lt) && rules.lt < rules.gte && (rules.lt <= this && this < rules.gte)? \'must be greater than or equal to %s or less than %s\'.format([rules.gte, rules.lt]) : \'\'\n\320\001\n\021timestamp.gte_lte\032\272\001has(rules.lte) && rules.lte >= rules.gte && (this > rules.lte || this < rules.gte)? \'must be greater than or equal to %s and less than or equal to %s\'.format([rules.gte, rules.lte]) : \'\'\n\330\001\n\033timestamp.gte_lte_exclusive\032\270\001has(rules.lte) && rules.lte < rules.gte && (rules.lte < this && this < rules.gte)? \'must be greater than or equal to %s or less than or equal to %s\'.format([rules.gte, rules.lte]) : \'\'' + _globals['_TIMESTAMPRULES'].fields_by_name['gt_now']._loaded_options = None + _globals['_TIMESTAMPRULES'].fields_by_name['gt_now']._serialized_options = b'\302HT\nR\n\020timestamp.gt_now\032>(rules.gt_now && this < now) ? \'must be greater than now\' : \'\'' + _globals['_TIMESTAMPRULES'].fields_by_name['within']._loaded_options = None + _globals['_TIMESTAMPRULES'].fields_by_name['within']._serialized_options = b'\302H\201\001\n\177\n\020timestamp.within\032kthis < now-rules.within || this > now+rules.within ? \'must be within %s of now\'.format([rules.within]) : \'\'' + _globals['_TIMESTAMPRULES'].fields_by_name['example']._loaded_options = None + _globals['_TIMESTAMPRULES'].fields_by_name['example']._serialized_options = b'\302H\033\n\031\n\021timestamp.example\032\004true' + _globals['_IGNORE']._serialized_start=54642 + _globals['_IGNORE']._serialized_end=54803 + _globals['_KNOWNREGEX']._serialized_start=54805 + _globals['_KNOWNREGEX']._serialized_end=54915 + _globals['_RULE']._serialized_start=178 + _globals['_RULE']._serialized_end=258 + _globals['_MESSAGERULES']._serialized_start=261 + _globals['_MESSAGERULES']._serialized_end=422 + _globals['_MESSAGEONEOFRULE']._serialized_start=424 + _globals['_MESSAGEONEOFRULE']._serialized_end=494 + _globals['_ONEOFRULES']._serialized_start=496 + _globals['_ONEOFRULES']._serialized_end=536 + _globals['_FIELDRULES']._serialized_start=539 + _globals['_FIELDRULES']._serialized_end=1918 + _globals['_PREDEFINEDRULES']._serialized_start=1920 + _globals['_PREDEFINEDRULES']._serialized_end=2010 + _globals['_FLOATRULES']._serialized_start=2013 + _globals['_FLOATRULES']._serialized_end=5003 + _globals['_DOUBLERULES']._serialized_start=5006 + _globals['_DOUBLERULES']._serialized_end=8014 + _globals['_INT32RULES']._serialized_start=8017 + _globals['_INT32RULES']._serialized_end=10671 + _globals['_INT64RULES']._serialized_start=10674 + _globals['_INT64RULES']._serialized_end=13328 + _globals['_UINT32RULES']._serialized_start=13331 + _globals['_UINT32RULES']._serialized_end=16003 + _globals['_UINT64RULES']._serialized_start=16006 + _globals['_UINT64RULES']._serialized_end=18678 + _globals['_SINT32RULES']._serialized_start=18681 + _globals['_SINT32RULES']._serialized_end=21353 + _globals['_SINT64RULES']._serialized_start=21356 + _globals['_SINT64RULES']._serialized_end=24028 + _globals['_FIXED32RULES']._serialized_start=24031 + _globals['_FIXED32RULES']._serialized_end=26720 + _globals['_FIXED64RULES']._serialized_start=26723 + _globals['_FIXED64RULES']._serialized_end=29412 + _globals['_SFIXED32RULES']._serialized_start=29415 + _globals['_SFIXED32RULES']._serialized_end=32122 + _globals['_SFIXED64RULES']._serialized_start=32125 + _globals['_SFIXED64RULES']._serialized_end=34832 + _globals['_BOOLRULES']._serialized_start=34835 + _globals['_BOOLRULES']._serialized_end=35044 + _globals['_STRINGRULES']._serialized_start=35047 + _globals['_STRINGRULES']._serialized_end=43190 + _globals['_BYTESRULES']._serialized_start=43193 + _globals['_BYTESRULES']._serialized_end=45571 + _globals['_ENUMRULES']._serialized_start=45574 + _globals['_ENUMRULES']._serialized_end=46064 + _globals['_REPEATEDRULES']._serialized_start=46067 + _globals['_REPEATEDRULES']._serialized_end=46595 + _globals['_MAPRULES']._serialized_start=46598 + _globals['_MAPRULES']._serialized_end=47026 + _globals['_ANYRULES']._serialized_start=47028 + _globals['_ANYRULES']._serialized_end=47077 + _globals['_DURATIONRULES']._serialized_start=47080 + _globals['_DURATIONRULES']._serialized_end=50004 + _globals['_FIELDMASKRULES']._serialized_start=50007 + _globals['_FIELDMASKRULES']._serialized_end=50781 + _globals['_TIMESTAMPRULES']._serialized_start=50784 + _globals['_TIMESTAMPRULES']._serialized_end=53832 + _globals['_VIOLATIONS']._serialized_start=53834 + _globals['_VIOLATIONS']._serialized_end=53903 + _globals['_VIOLATION']._serialized_start=53906 + _globals['_VIOLATION']._serialized_end=54103 + _globals['_FIELDPATH']._serialized_start=54105 + _globals['_FIELDPATH']._serialized_end=54176 + _globals['_FIELDPATHELEMENT']._serialized_start=54179 + _globals['_FIELDPATHELEMENT']._serialized_end=54639 +# @@protoc_insertion_point(module_scope) diff --git a/src/authorizer/_grpc/buf/validate/validate_pb2_grpc.py b/src/authorizer/_grpc/buf/validate/validate_pb2_grpc.py new file mode 100644 index 0000000..2daafff --- /dev/null +++ b/src/authorizer/_grpc/buf/validate/validate_pb2_grpc.py @@ -0,0 +1,4 @@ +# Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT! +"""Client and server classes corresponding to protobuf-defined services.""" +import grpc + diff --git a/src/authorizer/_grpc/google/__init__.py b/src/authorizer/_grpc/google/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/authorizer/_grpc/google/api/__init__.py b/src/authorizer/_grpc/google/api/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/authorizer/_grpc/google/api/annotations_pb2.py b/src/authorizer/_grpc/google/api/annotations_pb2.py new file mode 100644 index 0000000..15a2734 --- /dev/null +++ b/src/authorizer/_grpc/google/api/annotations_pb2.py @@ -0,0 +1,37 @@ +# -*- coding: utf-8 -*- +# Generated by the protocol buffer compiler. DO NOT EDIT! +# NO CHECKED-IN PROTOBUF GENCODE +# source: google/api/annotations.proto +# Protobuf Python Version: 5.27.3 +"""Generated protocol buffer code.""" +from google.protobuf import descriptor as _descriptor +from google.protobuf import descriptor_pool as _descriptor_pool +from google.protobuf import runtime_version as _runtime_version +from google.protobuf import symbol_database as _symbol_database +from google.protobuf.internal import builder as _builder +_runtime_version.ValidateProtobufRuntimeVersion( + _runtime_version.Domain.PUBLIC, + 5, + 27, + 3, + '', + 'google/api/annotations.proto' +) +# @@protoc_insertion_point(imports) + +_sym_db = _symbol_database.Default() + + +from authorizer._grpc.google.api import http_pb2 as google_dot_api_dot_http__pb2 +from google.protobuf import descriptor_pb2 as google_dot_protobuf_dot_descriptor__pb2 + + +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x1cgoogle/api/annotations.proto\x12\ngoogle.api\x1a\x15google/api/http.proto\x1a google/protobuf/descriptor.proto:K\n\x04http\x12\x1e.google.protobuf.MethodOptions\x18\xb0\xca\xbc\" \x01(\x0b\x32\x14.google.api.HttpRuleR\x04httpB\xae\x01\n\x0e\x63om.google.apiB\x10\x41nnotationsProtoP\x01ZAgoogle.golang.org/genproto/googleapis/api/annotations;annotations\xa2\x02\x03GAX\xaa\x02\nGoogle.Api\xca\x02\nGoogle\\Api\xe2\x02\x16Google\\Api\\GPBMetadata\xea\x02\x0bGoogle::Apib\x06proto3') + +_globals = globals() +_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) +_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'google.api.annotations_pb2', _globals) +if not _descriptor._USE_C_DESCRIPTORS: + _globals['DESCRIPTOR']._loaded_options = None + _globals['DESCRIPTOR']._serialized_options = b'\n\016com.google.apiB\020AnnotationsProtoP\001ZAgoogle.golang.org/genproto/googleapis/api/annotations;annotations\242\002\003GAX\252\002\nGoogle.Api\312\002\nGoogle\\Api\342\002\026Google\\Api\\GPBMetadata\352\002\013Google::Api' +# @@protoc_insertion_point(module_scope) diff --git a/src/authorizer/_grpc/google/api/annotations_pb2_grpc.py b/src/authorizer/_grpc/google/api/annotations_pb2_grpc.py new file mode 100644 index 0000000..2daafff --- /dev/null +++ b/src/authorizer/_grpc/google/api/annotations_pb2_grpc.py @@ -0,0 +1,4 @@ +# Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT! +"""Client and server classes corresponding to protobuf-defined services.""" +import grpc + diff --git a/src/authorizer/_grpc/google/api/http_pb2.py b/src/authorizer/_grpc/google/api/http_pb2.py new file mode 100644 index 0000000..13e2b8d --- /dev/null +++ b/src/authorizer/_grpc/google/api/http_pb2.py @@ -0,0 +1,41 @@ +# -*- coding: utf-8 -*- +# Generated by the protocol buffer compiler. DO NOT EDIT! +# NO CHECKED-IN PROTOBUF GENCODE +# source: google/api/http.proto +# Protobuf Python Version: 5.27.3 +"""Generated protocol buffer code.""" +from google.protobuf import descriptor as _descriptor +from google.protobuf import descriptor_pool as _descriptor_pool +from google.protobuf import runtime_version as _runtime_version +from google.protobuf import symbol_database as _symbol_database +from google.protobuf.internal import builder as _builder +_runtime_version.ValidateProtobufRuntimeVersion( + _runtime_version.Domain.PUBLIC, + 5, + 27, + 3, + '', + 'google/api/http.proto' +) +# @@protoc_insertion_point(imports) + +_sym_db = _symbol_database.Default() + + + + +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x15google/api/http.proto\x12\ngoogle.api\"y\n\x04Http\x12*\n\x05rules\x18\x01 \x03(\x0b\x32\x14.google.api.HttpRuleR\x05rules\x12\x45\n\x1f\x66ully_decode_reserved_expansion\x18\x02 \x01(\x08R\x1c\x66ullyDecodeReservedExpansion\"\xda\x02\n\x08HttpRule\x12\x1a\n\x08selector\x18\x01 \x01(\tR\x08selector\x12\x12\n\x03get\x18\x02 \x01(\tH\x00R\x03get\x12\x12\n\x03put\x18\x03 \x01(\tH\x00R\x03put\x12\x14\n\x04post\x18\x04 \x01(\tH\x00R\x04post\x12\x18\n\x06\x64\x65lete\x18\x05 \x01(\tH\x00R\x06\x64\x65lete\x12\x16\n\x05patch\x18\x06 \x01(\tH\x00R\x05patch\x12\x37\n\x06\x63ustom\x18\x08 \x01(\x0b\x32\x1d.google.api.CustomHttpPatternH\x00R\x06\x63ustom\x12\x12\n\x04\x62ody\x18\x07 \x01(\tR\x04\x62ody\x12#\n\rresponse_body\x18\x0c \x01(\tR\x0cresponseBody\x12\x45\n\x13\x61\x64\x64itional_bindings\x18\x0b \x03(\x0b\x32\x14.google.api.HttpRuleR\x12\x61\x64\x64itionalBindingsB\t\n\x07pattern\";\n\x11\x43ustomHttpPattern\x12\x12\n\x04kind\x18\x01 \x01(\tR\x04kind\x12\x12\n\x04path\x18\x02 \x01(\tR\x04pathB\xa7\x01\n\x0e\x63om.google.apiB\tHttpProtoP\x01ZAgoogle.golang.org/genproto/googleapis/api/annotations;annotations\xa2\x02\x03GAX\xaa\x02\nGoogle.Api\xca\x02\nGoogle\\Api\xe2\x02\x16Google\\Api\\GPBMetadata\xea\x02\x0bGoogle::Apib\x06proto3') + +_globals = globals() +_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) +_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'google.api.http_pb2', _globals) +if not _descriptor._USE_C_DESCRIPTORS: + _globals['DESCRIPTOR']._loaded_options = None + _globals['DESCRIPTOR']._serialized_options = b'\n\016com.google.apiB\tHttpProtoP\001ZAgoogle.golang.org/genproto/googleapis/api/annotations;annotations\242\002\003GAX\252\002\nGoogle.Api\312\002\nGoogle\\Api\342\002\026Google\\Api\\GPBMetadata\352\002\013Google::Api' + _globals['_HTTP']._serialized_start=37 + _globals['_HTTP']._serialized_end=158 + _globals['_HTTPRULE']._serialized_start=161 + _globals['_HTTPRULE']._serialized_end=507 + _globals['_CUSTOMHTTPPATTERN']._serialized_start=509 + _globals['_CUSTOMHTTPPATTERN']._serialized_end=568 +# @@protoc_insertion_point(module_scope) diff --git a/src/authorizer/_grpc/google/api/http_pb2_grpc.py b/src/authorizer/_grpc/google/api/http_pb2_grpc.py new file mode 100644 index 0000000..2daafff --- /dev/null +++ b/src/authorizer/_grpc/google/api/http_pb2_grpc.py @@ -0,0 +1,4 @@ +# Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT! +"""Client and server classes corresponding to protobuf-defined services.""" +import grpc + diff --git a/src/authorizer/_grpc_transport.py b/src/authorizer/_grpc_transport.py new file mode 100644 index 0000000..488b9d2 --- /dev/null +++ b/src/authorizer/_grpc_transport.py @@ -0,0 +1,146 @@ +"""Lazy gRPC transport for the Authorizer SDK. + +grpc + protobuf are optional (the ``grpc`` extra). Everything here imports them +lazily so the SDK works without them when protocol != "grpc". +""" + +from __future__ import annotations + +from typing import Any +from urllib.parse import urlparse + +from ._core import ClientConfig +from ._proto import build_message, message_to_dict, unwrap_field +from .exceptions import AuthorizerError + +_MISSING_MSG = ( + "protocol='grpc' requires the optional gRPC dependencies. " + "Install them with: pip install 'authorizer-py[grpc]'" +) + + +def _require_grpc() -> Any: + try: + import grpc # noqa: F401 + except ImportError as e: # pragma: no cover - exercised via tests w/o grpc + raise AuthorizerError(_MISSING_MSG) from e + return grpc + + +# The server's gRPC listener default port (separate from the HTTP port). +GRPC_DEFAULT_PORT = 9091 + + +def _target_and_secure(authorizer_url: str, grpc_endpoint: str = "") -> tuple[str, bool]: + """Return (host:port, use_tls) for a gRPC channel. + + When ``grpc_endpoint`` is set it is dialed verbatim. Otherwise the host is + derived from ``authorizer_url`` and port :data:`GRPC_DEFAULT_PORT` is used + (the server's gRPC listener runs on a separate port, not the HTTP port). + """ + parsed = urlparse(authorizer_url) + secure = parsed.scheme == "https" + if grpc_endpoint: + return grpc_endpoint, secure + host = parsed.hostname or "localhost" + return f"{host}:{GRPC_DEFAULT_PORT}", secure + + +def grpc_metadata(config: ClientConfig, per_call: dict[str, str] | None) -> list[tuple[str, str]]: + """Build gRPC metadata mirroring the HTTP identity/admin headers (lowercased).""" + md: dict[str, str] = { + "x-authorizer-url": config.authorizer_url, + "x-authorizer-client-id": config.client_id, + } + if config.admin_secret: + md["x-authorizer-admin-secret"] = config.admin_secret + for k, v in config.extra_headers.items(): + md[k.lower()] = v + if per_call: + for k, v in per_call.items(): + md[k.lower()] = v + return list(md.items()) + + +def make_channel(authorizer_url: str, grpc_endpoint: str = "") -> Any: + """Create a synchronous gRPC channel.""" + grpc = _require_grpc() + target, secure = _target_and_secure(authorizer_url, grpc_endpoint) + if secure: + return grpc.secure_channel(target, grpc.ssl_channel_credentials()) + return grpc.insecure_channel(target) + + +def make_async_channel(authorizer_url: str, grpc_endpoint: str = "") -> Any: + """Create an asynchronous (grpc.aio) gRPC channel.""" + grpc = _require_grpc() + target, secure = _target_and_secure(authorizer_url, grpc_endpoint) + if secure: + return grpc.aio.secure_channel(target, grpc.ssl_channel_credentials()) + return grpc.aio.insecure_channel(target) + + +def load_stubs() -> Any: + """Import the vendored generated stub modules (lazily).""" + _require_grpc() + from ._grpc.authorizer.v1 import ( + admin_pb2, + admin_pb2_grpc, + authorizer_pb2, + authorizer_pb2_grpc, + ) + + return admin_pb2, admin_pb2_grpc, authorizer_pb2, authorizer_pb2_grpc + + +def _resolve(spec: Any, admin: bool) -> tuple[Any, Any, Any]: + """Return (stub_class, pb2_module, channel-less). Picks admin vs public modules.""" + admin_pb2, admin_pb2_grpc, authorizer_pb2, authorizer_pb2_grpc = load_stubs() + if admin: + return admin_pb2_grpc.AuthorizerAdminServiceStub, admin_pb2, None + return authorizer_pb2_grpc.AuthorizerServiceStub, authorizer_pb2, None + + +def grpc_call( + channel: Any, + spec: Any, + data: dict[str, Any] | None, + metadata: list[tuple[str, str]], + admin: bool, +) -> dict[str, Any] | None: + """Invoke a unary gRPC method on a synchronous channel and return a dict.""" + grpc = _require_grpc() + stub_cls, pb2, _ = _resolve(spec, admin) + stub = stub_cls(channel) + request = build_message(getattr(pb2, spec.grpc_request), data or {}) + try: + response = getattr(stub, spec.grpc_method)(request, metadata=metadata) + except grpc.RpcError as e: # pragma: no cover - exercised live + raise AuthorizerError(_rpc_message(e)) from e + return unwrap_field(message_to_dict(response), spec.grpc_response_unwrap) + + +async def grpc_acall( + channel: Any, + spec: Any, + data: dict[str, Any] | None, + metadata: list[tuple[str, str]], + admin: bool, +) -> dict[str, Any] | None: + """Invoke a unary gRPC method on a grpc.aio channel and return a dict.""" + grpc = _require_grpc() + stub_cls, pb2, _ = _resolve(spec, admin) + stub = stub_cls(channel) + request = build_message(getattr(pb2, spec.grpc_request), data or {}) + try: + response = await getattr(stub, spec.grpc_method)(request, metadata=metadata) + except grpc.RpcError as e: # pragma: no cover - exercised live + raise AuthorizerError(_rpc_message(e)) from e + return unwrap_field(message_to_dict(response), spec.grpc_response_unwrap) + + +def _rpc_message(e: Any) -> str: + try: + return str(e.details() or e.code()) + except Exception: # pragma: no cover - defensive + return str(e) diff --git a/src/authorizer/_proto.py b/src/authorizer/_proto.py new file mode 100644 index 0000000..8c5bb4c --- /dev/null +++ b/src/authorizer/_proto.py @@ -0,0 +1,153 @@ +"""Protobuf (protojson) helpers shared by the REST and gRPC transports. + +Only depends on ``protobuf`` + the vendored ``_pb2`` modules — NOT ``grpcio``. +The REST protocol uses this to parse grpc-gateway JSON correctly (int64/uint64 +serialize as STRINGS and payloads are wrapped in a single proto field), reusing +the same message<->dict mapping the gRPC transport applies to proto messages. +""" + +from __future__ import annotations + +from typing import Any + + +def _load_pb2() -> tuple[Any, Any]: + """Import the vendored proto message modules (admin + public).""" + from ._grpc.authorizer.v1 import admin_pb2, authorizer_pb2 + + return admin_pb2, authorizer_pb2 + + +def _response_message_cls(grpc_method: str, admin: bool) -> Any: + """Resolve the proto *response* message class for an RPC by its method name. + + Uses the gRPC service descriptor as the source of truth for each RPC's + output type (so REST and gRPC agree on shapes). + """ + from google.protobuf import message_factory + + admin_pb2, authorizer_pb2 = _load_pb2() + fd = (admin_pb2 if admin else authorizer_pb2).DESCRIPTOR + svc_name = "AuthorizerAdminService" if admin else "AuthorizerService" + method = fd.services_by_name[svc_name].methods_by_name[grpc_method] + return message_factory.GetMessageClass(method.output_type) + + +def parse_rest_proto(body: bytes, grpc_method: str, admin: bool, unwrap: str | None) -> Any: + """Parse a grpc-gateway REST body via protojson, then map to the SDK dict.""" + from google.protobuf import json_format + + msg_cls = _response_message_cls(grpc_method, admin) + msg = json_format.Parse(body, msg_cls(), ignore_unknown_fields=True) + return unwrap_field(message_to_dict(msg), unwrap) + + +def build_message(message_cls: Any, payload: dict[str, Any]) -> Any: + """Convert a snake_case dict into a proto message (ignoring unknown keys). + + Flat free-form maps (``app_data``, ``headers``, ``claims`` — the GraphQL + ``Map`` scalar) are wrapped into the proto AppData shape ``{"value": {...}}`` + so callers pass the same flat dict regardless of protocol. + """ + from google.protobuf.json_format import ParseDict + + msg = message_cls() + return ParseDict(_wrap(payload, msg.DESCRIPTOR), msg, ignore_unknown_fields=True) + + +def _wrap(value: Any, descriptor: Any) -> Any: + from google.protobuf.descriptor import FieldDescriptor + + if not isinstance(value, dict): + return value + out: dict[str, Any] = {} + fields = {f.name: f for f in descriptor.fields} + for key, val in value.items(): + field = fields.get(key) + if field is None or field.type != FieldDescriptor.TYPE_MESSAGE: + out[key] = val + continue + if field.message_type.full_name == "authorizer.v1.AppData": + # SDK contract: free-form maps are flat; wrap into the proto AppData. + out[key] = {"value": val} if isinstance(val, dict) else val + elif field.label == FieldDescriptor.LABEL_REPEATED and isinstance(val, list): + out[key] = [_wrap(v, field.message_type) for v in val] + else: + out[key] = _wrap(val, field.message_type) + return out + + +def message_to_dict(message: Any) -> dict[str, Any]: + """Convert a proto message to a snake_case dict matching the GraphQL/REST shape. + + Two proto-JSON quirks are normalized so the SDK dataclasses see the same + shape regardless of protocol: + + - int64 fields serialize as strings -> coerced back to ``int``. + - AppData wraps a free-form map as ``{"value": {...}}`` -> flattened to the + inner map (matching the GraphQL ``Map`` scalar). + """ + from google.protobuf.json_format import MessageToDict + + raw = MessageToDict( + message, + preserving_proto_field_name=True, + always_print_fields_with_no_presence=True, + ) + return _normalize(raw, message.DESCRIPTOR) # type: ignore[no-any-return] + + +def unwrap_field(payload: dict[str, Any], field: str | None) -> dict[str, Any] | None: + if field is None: + return payload + inner = payload.get(field) + return inner if isinstance(inner, dict) else None + + +def _normalize(value: Any, descriptor: Any) -> Any: + if not isinstance(value, dict): + return value + # AppData: {"value": } -> (the flat GraphQL Map). + if descriptor.full_name == "authorizer.v1.AppData": + return value.get("value") + out: dict[str, Any] = {} + fields = {f.name: f for f in descriptor.fields} + for key, val in value.items(): + field = fields.get(key) + if field is None: + out[key] = val + continue + out[key] = _normalize_field(val, field) + return out + + +def _normalize_field(val: Any, field: Any) -> Any: + from google.protobuf.descriptor import FieldDescriptor + + int_types = { + FieldDescriptor.TYPE_INT64, + FieldDescriptor.TYPE_UINT64, + FieldDescriptor.TYPE_SINT64, + FieldDescriptor.TYPE_FIXED64, + FieldDescriptor.TYPE_SFIXED64, + } + if field.label == FieldDescriptor.LABEL_REPEATED and isinstance(val, list): + if field.type == FieldDescriptor.TYPE_MESSAGE: + return [_normalize(v, field.message_type) for v in val] + if field.type in int_types: + return [_coerce_int(v) for v in val] + return val + if field.type == FieldDescriptor.TYPE_MESSAGE: + return _normalize(val, field.message_type) + if field.type in int_types: + return _coerce_int(val) + return val + + +def _coerce_int(val: Any) -> Any: + if isinstance(val, str): + try: + return int(val) + except ValueError: + return val + return val diff --git a/src/authorizer/_queries.py b/src/authorizer/_queries.py index 87924cf..dbdc8cf 100644 --- a/src/authorizer/_queries.py +++ b/src/authorizer/_queries.py @@ -108,3 +108,147 @@ "query listPermissions($data: ListPermissionsInput!)" "{ list_permissions(params: $data) { objects permissions { object relation } truncated } }" ) + +# --------------------------------------------------------------------------- # +# Admin (`_`-prefixed) operations. GraphQL fragments mirror the admin schema. +# --------------------------------------------------------------------------- # +RESPONSE_FRAGMENT = "message" +PAGINATION_FRAGMENT = "pagination { limit page offset total }" +WEBHOOK_FRAGMENT = ( + "id event_name event_description endpoint enabled headers created_at updated_at" +) +WEBHOOK_LOG_FRAGMENT = "id http_status response request webhook_id created_at updated_at" +EMAIL_TEMPLATE_FRAGMENT = "id event_name template design subject created_at updated_at" +AUDIT_LOG_FRAGMENT = ( + "id actor_id actor_type actor_email action resource_type resource_id " + "ip_address user_agent metadata created_at" +) +VERIFICATION_REQUEST_FRAGMENT = ( + "id identifier token email expires created_at updated_at nonce redirect_uri" +) + +ADMIN_LOGIN = ( + "mutation adminLogin($data: AdminLoginRequest!) " + "{ _admin_login(params: $data) { message } }" +) +ADMIN_SIGNUP = ( + "mutation adminSignup($data: AdminSignupRequest!) " + "{ _admin_signup(params: $data) { message } }" +) +ADMIN_USERS = ( + "query adminUsers($data: PaginatedRequest) " + f"{{ _users(params: $data) {{ {PAGINATION_FRAGMENT} users {{ {USER_FRAGMENT} }} }} }}" +) +ADMIN_USER = ( + "query adminUser($data: GetUserRequest!) " + f"{{ _user(params: $data) {{ {USER_FRAGMENT} }} }}" +) +ADMIN_UPDATE_USER = ( + "mutation adminUpdateUser($data: UpdateUserRequest!) " + f"{{ _update_user(params: $data) {{ {USER_FRAGMENT} }} }}" +) +ADMIN_DELETE_USER = ( + "mutation adminDeleteUser($data: DeleteUserRequest!) " + "{ _delete_user(params: $data) { message } }" +) +ADMIN_VERIFICATION_REQUESTS = ( + "query adminVerificationRequests($data: PaginatedRequest) " + f"{{ _verification_requests(params: $data) {{ {PAGINATION_FRAGMENT} " + f"verification_requests {{ {VERIFICATION_REQUEST_FRAGMENT} }} }} }}" +) +ADMIN_REVOKE_ACCESS = ( + "mutation adminRevokeAccess($data: UpdateAccessRequest!) " + "{ _revoke_access(param: $data) { message } }" +) +ADMIN_ENABLE_ACCESS = ( + "mutation adminEnableAccess($data: UpdateAccessRequest!) " + "{ _enable_access(param: $data) { message } }" +) +ADMIN_INVITE_MEMBERS = ( + "mutation adminInviteMembers($data: InviteMemberRequest!) " + f"{{ _invite_members(params: $data) {{ message Users {{ {USER_FRAGMENT} }} }} }}" +) +ADMIN_ADD_WEBHOOK = ( + "mutation adminAddWebhook($data: AddWebhookRequest!) " + "{ _add_webhook(params: $data) { message } }" +) +ADMIN_UPDATE_WEBHOOK = ( + "mutation adminUpdateWebhook($data: UpdateWebhookRequest!) " + "{ _update_webhook(params: $data) { message } }" +) +ADMIN_DELETE_WEBHOOK = ( + "mutation adminDeleteWebhook($data: WebhookRequest!) " + "{ _delete_webhook(params: $data) { message } }" +) +ADMIN_GET_WEBHOOK = ( + "query adminWebhook($data: WebhookRequest!) " + f"{{ _webhook(params: $data) {{ {WEBHOOK_FRAGMENT} }} }}" +) +ADMIN_WEBHOOKS = ( + "query adminWebhooks($data: PaginatedRequest) " + f"{{ _webhooks(params: $data) {{ {PAGINATION_FRAGMENT} webhooks {{ {WEBHOOK_FRAGMENT} }} }} }}" +) +ADMIN_WEBHOOK_LOGS = ( + "query adminWebhookLogs($data: ListWebhookLogRequest) " + f"{{ _webhook_logs(params: $data) {{ {PAGINATION_FRAGMENT} " + f"webhook_logs {{ {WEBHOOK_LOG_FRAGMENT} }} }} }}" +) +ADMIN_TEST_ENDPOINT = ( + "mutation adminTestEndpoint($data: TestEndpointRequest!) " + "{ _test_endpoint(params: $data) { http_status response } }" +) +ADMIN_ADD_EMAIL_TEMPLATE = ( + "mutation adminAddEmailTemplate($data: AddEmailTemplateRequest!) " + "{ _add_email_template(params: $data) { message } }" +) +ADMIN_UPDATE_EMAIL_TEMPLATE = ( + "mutation adminUpdateEmailTemplate($data: UpdateEmailTemplateRequest!) " + "{ _update_email_template(params: $data) { message } }" +) +ADMIN_DELETE_EMAIL_TEMPLATE = ( + "mutation adminDeleteEmailTemplate($data: DeleteEmailTemplateRequest!) " + "{ _delete_email_template(params: $data) { message } }" +) +ADMIN_EMAIL_TEMPLATES = ( + "query adminEmailTemplates($data: PaginatedRequest) " + f"{{ _email_templates(params: $data) {{ {PAGINATION_FRAGMENT} " + f"email_templates {{ {EMAIL_TEMPLATE_FRAGMENT} }} }} }}" +) +ADMIN_AUDIT_LOGS = ( + "query adminAuditLogs($data: ListAuditLogRequest) " + f"{{ _audit_logs(params: $data) {{ {PAGINATION_FRAGMENT} " + f"audit_logs {{ {AUDIT_LOG_FRAGMENT} }} }} }}" +) +ADMIN_UPDATE_ENV = ( + "mutation adminUpdateEnv($data: UpdateEnvRequest!) " + "{ _update_env(params: $data) { message } }" +) +ADMIN_GENERATE_JWT_KEYS = ( + "mutation adminGenerateJwtKeys($data: GenerateJWTKeysRequest!) " + "{ _generate_jwt_keys(params: $data) { secret public_key private_key } }" +) +ADMIN_FGA_WRITE_MODEL = ( + "mutation adminFgaWriteModel($data: FgaWriteModelInput!) " + "{ _fga_write_model(params: $data) { id dsl } }" +) +ADMIN_FGA_WRITE_TUPLES = ( + "mutation adminFgaWriteTuples($data: FgaWriteTuplesInput!) " + "{ _fga_write_tuples(params: $data) { message } }" +) +ADMIN_FGA_DELETE_TUPLES = ( + "mutation adminFgaDeleteTuples($data: FgaWriteTuplesInput!) " + "{ _fga_delete_tuples(params: $data) { message } }" +) +ADMIN_FGA_READ_TUPLES = ( + "query adminFgaReadTuples($data: FgaReadTuplesInput!) " + "{ _fga_read_tuples(params: $data) " + "{ tuples { user relation object } continuation_token } }" +) +ADMIN_FGA_LIST_USERS = ( + "query adminFgaListUsers($data: FgaListUsersInput!) " + "{ _fga_list_users(params: $data) { users } }" +) +ADMIN_FGA_EXPAND = ( + "query adminFgaExpand($data: FgaExpandInput!) " + "{ _fga_expand(params: $data) { tree } }" +) diff --git a/src/authorizer/admin_client.py b/src/authorizer/admin_client.py new file mode 100644 index 0000000..ae39f5c --- /dev/null +++ b/src/authorizer/admin_client.py @@ -0,0 +1,269 @@ +"""Synchronous Authorizer admin client. + +Admin auth uses the ``x-authorizer-admin-secret`` header (HTTP) / metadata key +(gRPC). The default mechanism is the secret; the admin session cookie flow +(:meth:`admin_login` -> Set-Cookie) is also supported. +""" + +from __future__ import annotations + +from types import TracebackType +from typing import Any + +import httpx + +from . import _dispatch as d +from . import types as t +from ._core import ( + PROTOCOLS, + ClientConfig, + RequestSpec, + parse_graphql_response, + parse_rest, + prepare_http, + unsupported_protocol_error, +) +from ._dispatch import MethodSpec +from .exceptions import AuthorizerConnectionError + + +class AuthorizerAdminClient: + """Synchronous client for Authorizer's super-admin-only API surface.""" + + _ADMIN = True + + def __init__( + self, + authorizer_url: str, + admin_secret: str, + extra_headers: dict[str, str] | None = None, + protocol: str = "graphql", + grpc_endpoint: str = "", + ) -> None: + if not authorizer_url or not authorizer_url.strip(): + raise ValueError("authorizer_url is required") + if not admin_secret or not admin_secret.strip(): + raise ValueError("admin_secret is required") + if protocol not in PROTOCOLS: + raise ValueError(f"protocol must be one of {PROTOCOLS}, got {protocol!r}") + self._config = ClientConfig( + client_id="", + authorizer_url=authorizer_url.strip().rstrip("/"), + redirect_url="", + extra_headers=dict(extra_headers or {}), + protocol=protocol, + admin_secret=admin_secret, + grpc_endpoint=grpc_endpoint.strip(), + ) + self._http = httpx.Client() + self._channel: Any = None + + # -- lifecycle -------------------------------------------------------- # + def close(self) -> None: + self._http.close() + if self._channel is not None: + self._channel.close() + self._channel = None + + def __enter__(self) -> AuthorizerAdminClient: + return self + + def __exit__( + self, + exc_type: type[BaseException] | None, + exc: BaseException | None, + tb: TracebackType | None, + ) -> None: + self.close() + + # -- dispatch --------------------------------------------------------- # + def _send(self, spec: RequestSpec) -> httpx.Response: + try: + return self._http.request(spec.method, spec.url, json=spec.json, headers=spec.headers) + except httpx.HTTPError as e: + raise AuthorizerConnectionError(str(e)) from e + + def _invoke( + self, + method: str, + spec: MethodSpec, + data: dict[str, Any] | None = None, + headers: dict[str, str] | None = None, + ) -> dict[str, Any] | None: + proto = self._config.protocol + if proto not in spec.protocols: + raise unsupported_protocol_error(method, proto, spec.protocols) + if proto == "grpc": + from . import _grpc_transport as g + + if self._channel is None: + self._channel = g.make_channel( + self._config.authorizer_url, self._config.grpc_endpoint + ) + md = g.grpc_metadata(self._config, headers) + return g.grpc_call(self._channel, spec, data, md, self._ADMIN) + req, kind, unwrap = prepare_http(self._config, spec, data, headers) + res = self._send(req) + if kind == "rest": + return parse_rest(spec, res.status_code, res.content, unwrap, self._ADMIN) + return parse_graphql_response(res.status_code, res.content, unwrap or "") + + # -- admin auth + meta ------------------------------------------------ # + def admin_login(self, req: t.AdminLoginRequest) -> t.GenericResponse: + res = self._invoke("admin_login", d.ADMIN["admin_login"], req.to_dict()) + return t.GenericResponse.from_dict(res or {}) + + def admin_logout(self) -> t.GenericResponse: + res = self._invoke("admin_logout", d.ADMIN["admin_logout"], None) + return t.GenericResponse.from_dict(res or {}) + + def admin_session(self) -> t.GenericResponse: + res = self._invoke("admin_session", d.ADMIN["admin_session"], None) + return t.GenericResponse.from_dict(res or {}) + + def admin_meta(self) -> t.AdminMeta: + res = self._invoke("admin_meta", d.ADMIN["admin_meta"], None) + return t.AdminMeta.from_dict(res or {}) + + def admin_signup(self, req: t.AdminSignupRequest) -> t.GenericResponse: + res = self._invoke("admin_signup", d.ADMIN["admin_signup"], req.to_dict()) + return t.GenericResponse.from_dict(res or {}) + + def update_env(self, env: dict[str, Any]) -> t.GenericResponse: + res = self._invoke("update_env", d.ADMIN["update_env"], env) + return t.GenericResponse.from_dict(res or {}) + + def generate_jwt_keys(self, req: t.GenerateJWTKeysRequest) -> t.GenerateJWTKeysResponse: + res = self._invoke("generate_jwt_keys", d.ADMIN["generate_jwt_keys"], req.to_dict()) + return t.GenerateJWTKeysResponse.from_dict(res or {}) + + # -- users ------------------------------------------------------------ # + def users(self, req: t.PaginatedRequest | None = None) -> t.UsersResponse: + res = self._invoke("users", d.ADMIN["users"], req.to_dict() if req else None) + return t.UsersResponse.from_dict(res or {}) + + def user(self, req: t.GetUserRequest) -> t.User: + res = self._invoke("user", d.ADMIN["user"], req.to_dict()) + return t.User.from_dict(res or {}) + + def update_user(self, req: t.UpdateUserRequest) -> t.User: + res = self._invoke("update_user", d.ADMIN["update_user"], req.to_dict()) + return t.User.from_dict(res or {}) + + def delete_user(self, req: t.DeleteUserRequest) -> t.GenericResponse: + """Destructive: permanently deletes the user and associated OTP/verification data.""" + res = self._invoke("delete_user", d.ADMIN["delete_user"], req.to_dict()) + return t.GenericResponse.from_dict(res or {}) + + def verification_requests( + self, req: t.PaginatedRequest | None = None + ) -> t.VerificationRequestsResponse: + res = self._invoke( + "verification_requests", d.ADMIN["verification_requests"], + req.to_dict() if req else None, + ) + return t.VerificationRequestsResponse.from_dict(res or {}) + + # -- access ----------------------------------------------------------- # + def revoke_access(self, req: t.UpdateAccessRequest) -> t.GenericResponse: + res = self._invoke("revoke_access", d.ADMIN["revoke_access"], req.to_dict()) + return t.GenericResponse.from_dict(res or {}) + + def enable_access(self, req: t.UpdateAccessRequest) -> t.GenericResponse: + res = self._invoke("enable_access", d.ADMIN["enable_access"], req.to_dict()) + return t.GenericResponse.from_dict(res or {}) + + def invite_members(self, req: t.InviteMembersRequest) -> t.InviteMembersResponse: + res = self._invoke("invite_members", d.ADMIN["invite_members"], req.to_dict()) + return t.InviteMembersResponse.from_dict(res or {}) + + # -- webhooks --------------------------------------------------------- # + def add_webhook(self, req: t.AddWebhookRequest) -> t.GenericResponse: + res = self._invoke("add_webhook", d.ADMIN["add_webhook"], req.to_dict()) + return t.GenericResponse.from_dict(res or {}) + + def update_webhook(self, req: t.UpdateWebhookRequest) -> t.GenericResponse: + res = self._invoke("update_webhook", d.ADMIN["update_webhook"], req.to_dict()) + return t.GenericResponse.from_dict(res or {}) + + def delete_webhook(self, req: t.WebhookRequest) -> t.GenericResponse: + """Destructive: permanently deletes the webhook.""" + res = self._invoke("delete_webhook", d.ADMIN["delete_webhook"], req.to_dict()) + return t.GenericResponse.from_dict(res or {}) + + def get_webhook(self, req: t.WebhookRequest) -> t.Webhook: + res = self._invoke("get_webhook", d.ADMIN["get_webhook"], req.to_dict()) + return t.Webhook.from_dict(res or {}) + + def webhooks(self, req: t.PaginatedRequest | None = None) -> t.WebhooksResponse: + res = self._invoke("webhooks", d.ADMIN["webhooks"], req.to_dict() if req else None) + return t.WebhooksResponse.from_dict(res or {}) + + def webhook_logs(self, req: t.ListWebhookLogRequest | None = None) -> t.WebhookLogsResponse: + res = self._invoke("webhook_logs", d.ADMIN["webhook_logs"], req.to_dict() if req else None) + return t.WebhookLogsResponse.from_dict(res or {}) + + def test_endpoint(self, req: t.TestEndpointRequest) -> t.TestEndpointResponse: + res = self._invoke("test_endpoint", d.ADMIN["test_endpoint"], req.to_dict()) + return t.TestEndpointResponse.from_dict(res or {}) + + # -- email templates -------------------------------------------------- # + def add_email_template(self, req: t.AddEmailTemplateRequest) -> t.GenericResponse: + res = self._invoke("add_email_template", d.ADMIN["add_email_template"], req.to_dict()) + return t.GenericResponse.from_dict(res or {}) + + def update_email_template(self, req: t.UpdateEmailTemplateRequest) -> t.GenericResponse: + res = self._invoke("update_email_template", d.ADMIN["update_email_template"], req.to_dict()) + return t.GenericResponse.from_dict(res or {}) + + def delete_email_template(self, req: t.DeleteEmailTemplateRequest) -> t.GenericResponse: + """Destructive: permanently deletes the email template.""" + res = self._invoke("delete_email_template", d.ADMIN["delete_email_template"], req.to_dict()) + return t.GenericResponse.from_dict(res or {}) + + def email_templates(self, req: t.PaginatedRequest | None = None) -> t.EmailTemplatesResponse: + res = self._invoke( + "email_templates", d.ADMIN["email_templates"], req.to_dict() if req else None + ) + return t.EmailTemplatesResponse.from_dict(res or {}) + + # -- audit ------------------------------------------------------------ # + def audit_logs(self, req: t.ListAuditLogRequest | None = None) -> t.AuditLogsResponse: + res = self._invoke("audit_logs", d.ADMIN["audit_logs"], req.to_dict() if req else None) + return t.AuditLogsResponse.from_dict(res or {}) + + # -- FGA -------------------------------------------------------------- # + def fga_get_model(self) -> t.FgaModel: + res = self._invoke("fga_get_model", d.ADMIN["fga_get_model"], None) + return t.FgaModel.from_dict(res or {}) + + def fga_write_model(self, req: t.FgaWriteModelRequest) -> t.FgaModel: + """Destructive: replaces the active fine-grained authorization model.""" + res = self._invoke("fga_write_model", d.ADMIN["fga_write_model"], req.to_dict()) + return t.FgaModel.from_dict(res or {}) + + def fga_write_tuples(self, req: t.FgaWriteTuplesRequest) -> t.GenericResponse: + res = self._invoke("fga_write_tuples", d.ADMIN["fga_write_tuples"], req.to_dict()) + return t.GenericResponse.from_dict(res or {}) + + def fga_delete_tuples(self, req: t.FgaWriteTuplesRequest) -> t.GenericResponse: + """Destructive: removes the given relationship tuples.""" + res = self._invoke("fga_delete_tuples", d.ADMIN["fga_delete_tuples"], req.to_dict()) + return t.GenericResponse.from_dict(res or {}) + + def fga_read_tuples(self, req: t.FgaReadTuplesRequest) -> t.FgaReadTuplesResponse: + res = self._invoke("fga_read_tuples", d.ADMIN["fga_read_tuples"], req.to_dict()) + return t.FgaReadTuplesResponse.from_dict(res or {}) + + def fga_list_users(self, req: t.FgaListUsersRequest) -> t.FgaListUsersResponse: + res = self._invoke("fga_list_users", d.ADMIN["fga_list_users"], req.to_dict()) + return t.FgaListUsersResponse.from_dict(res or {}) + + def fga_expand(self, req: t.FgaExpandRequest) -> t.FgaExpandResponse: + res = self._invoke("fga_expand", d.ADMIN["fga_expand"], req.to_dict()) + return t.FgaExpandResponse.from_dict(res or {}) + + def fga_reset(self) -> t.GenericResponse: + """Destructive: deletes the entire fine-grained authorization store.""" + res = self._invoke("fga_reset", d.ADMIN["fga_reset"], None) + return t.GenericResponse.from_dict(res or {}) diff --git a/src/authorizer/async_admin_client.py b/src/authorizer/async_admin_client.py new file mode 100644 index 0000000..64e8d72 --- /dev/null +++ b/src/authorizer/async_admin_client.py @@ -0,0 +1,280 @@ +"""Asynchronous Authorizer admin client (parity with AuthorizerAdminClient).""" + +from __future__ import annotations + +from types import TracebackType +from typing import Any + +import httpx + +from . import _dispatch as d +from . import types as t +from ._core import ( + PROTOCOLS, + ClientConfig, + RequestSpec, + parse_graphql_response, + parse_rest, + prepare_http, + unsupported_protocol_error, +) +from ._dispatch import MethodSpec +from .exceptions import AuthorizerConnectionError + + +class AsyncAuthorizerAdminClient: + """Asynchronous client for Authorizer's super-admin-only API surface.""" + + _ADMIN = True + + def __init__( + self, + authorizer_url: str, + admin_secret: str, + extra_headers: dict[str, str] | None = None, + protocol: str = "graphql", + grpc_endpoint: str = "", + ) -> None: + if not authorizer_url or not authorizer_url.strip(): + raise ValueError("authorizer_url is required") + if not admin_secret or not admin_secret.strip(): + raise ValueError("admin_secret is required") + if protocol not in PROTOCOLS: + raise ValueError(f"protocol must be one of {PROTOCOLS}, got {protocol!r}") + self._config = ClientConfig( + client_id="", + authorizer_url=authorizer_url.strip().rstrip("/"), + redirect_url="", + extra_headers=dict(extra_headers or {}), + protocol=protocol, + admin_secret=admin_secret, + grpc_endpoint=grpc_endpoint.strip(), + ) + self._http = httpx.AsyncClient() + self._channel: Any = None + + # -- lifecycle -------------------------------------------------------- # + async def aclose(self) -> None: + await self._http.aclose() + if self._channel is not None: + await self._channel.close() + self._channel = None + + async def __aenter__(self) -> AsyncAuthorizerAdminClient: + return self + + async def __aexit__( + self, + exc_type: type[BaseException] | None, + exc: BaseException | None, + tb: TracebackType | None, + ) -> None: + await self.aclose() + + # -- dispatch --------------------------------------------------------- # + async def _send(self, spec: RequestSpec) -> httpx.Response: + try: + return await self._http.request( + spec.method, spec.url, json=spec.json, headers=spec.headers + ) + except httpx.HTTPError as e: + raise AuthorizerConnectionError(str(e)) from e + + async def _invoke( + self, + method: str, + spec: MethodSpec, + data: dict[str, Any] | None = None, + headers: dict[str, str] | None = None, + ) -> dict[str, Any] | None: + proto = self._config.protocol + if proto not in spec.protocols: + raise unsupported_protocol_error(method, proto, spec.protocols) + if proto == "grpc": + from . import _grpc_transport as g + + if self._channel is None: + self._channel = g.make_async_channel( + self._config.authorizer_url, self._config.grpc_endpoint + ) + md = g.grpc_metadata(self._config, headers) + return await g.grpc_acall(self._channel, spec, data, md, self._ADMIN) + req, kind, unwrap = prepare_http(self._config, spec, data, headers) + res = await self._send(req) + if kind == "rest": + return parse_rest(spec, res.status_code, res.content, unwrap, self._ADMIN) + return parse_graphql_response(res.status_code, res.content, unwrap or "") + + # -- admin auth + meta ------------------------------------------------ # + async def admin_login(self, req: t.AdminLoginRequest) -> t.GenericResponse: + res = await self._invoke("admin_login", d.ADMIN["admin_login"], req.to_dict()) + return t.GenericResponse.from_dict(res or {}) + + async def admin_logout(self) -> t.GenericResponse: + res = await self._invoke("admin_logout", d.ADMIN["admin_logout"], None) + return t.GenericResponse.from_dict(res or {}) + + async def admin_session(self) -> t.GenericResponse: + res = await self._invoke("admin_session", d.ADMIN["admin_session"], None) + return t.GenericResponse.from_dict(res or {}) + + async def admin_meta(self) -> t.AdminMeta: + res = await self._invoke("admin_meta", d.ADMIN["admin_meta"], None) + return t.AdminMeta.from_dict(res or {}) + + async def admin_signup(self, req: t.AdminSignupRequest) -> t.GenericResponse: + res = await self._invoke("admin_signup", d.ADMIN["admin_signup"], req.to_dict()) + return t.GenericResponse.from_dict(res or {}) + + async def update_env(self, env: dict[str, Any]) -> t.GenericResponse: + res = await self._invoke("update_env", d.ADMIN["update_env"], env) + return t.GenericResponse.from_dict(res or {}) + + async def generate_jwt_keys( + self, req: t.GenerateJWTKeysRequest + ) -> t.GenerateJWTKeysResponse: + res = await self._invoke("generate_jwt_keys", d.ADMIN["generate_jwt_keys"], req.to_dict()) + return t.GenerateJWTKeysResponse.from_dict(res or {}) + + # -- users ------------------------------------------------------------ # + async def users(self, req: t.PaginatedRequest | None = None) -> t.UsersResponse: + res = await self._invoke("users", d.ADMIN["users"], req.to_dict() if req else None) + return t.UsersResponse.from_dict(res or {}) + + async def user(self, req: t.GetUserRequest) -> t.User: + res = await self._invoke("user", d.ADMIN["user"], req.to_dict()) + return t.User.from_dict(res or {}) + + async def update_user(self, req: t.UpdateUserRequest) -> t.User: + res = await self._invoke("update_user", d.ADMIN["update_user"], req.to_dict()) + return t.User.from_dict(res or {}) + + async def delete_user(self, req: t.DeleteUserRequest) -> t.GenericResponse: + """Destructive: permanently deletes the user and associated OTP/verification data.""" + res = await self._invoke("delete_user", d.ADMIN["delete_user"], req.to_dict()) + return t.GenericResponse.from_dict(res or {}) + + async def verification_requests( + self, req: t.PaginatedRequest | None = None + ) -> t.VerificationRequestsResponse: + res = await self._invoke( + "verification_requests", d.ADMIN["verification_requests"], + req.to_dict() if req else None, + ) + return t.VerificationRequestsResponse.from_dict(res or {}) + + # -- access ----------------------------------------------------------- # + async def revoke_access(self, req: t.UpdateAccessRequest) -> t.GenericResponse: + res = await self._invoke("revoke_access", d.ADMIN["revoke_access"], req.to_dict()) + return t.GenericResponse.from_dict(res or {}) + + async def enable_access(self, req: t.UpdateAccessRequest) -> t.GenericResponse: + res = await self._invoke("enable_access", d.ADMIN["enable_access"], req.to_dict()) + return t.GenericResponse.from_dict(res or {}) + + async def invite_members(self, req: t.InviteMembersRequest) -> t.InviteMembersResponse: + res = await self._invoke("invite_members", d.ADMIN["invite_members"], req.to_dict()) + return t.InviteMembersResponse.from_dict(res or {}) + + # -- webhooks --------------------------------------------------------- # + async def add_webhook(self, req: t.AddWebhookRequest) -> t.GenericResponse: + res = await self._invoke("add_webhook", d.ADMIN["add_webhook"], req.to_dict()) + return t.GenericResponse.from_dict(res or {}) + + async def update_webhook(self, req: t.UpdateWebhookRequest) -> t.GenericResponse: + res = await self._invoke("update_webhook", d.ADMIN["update_webhook"], req.to_dict()) + return t.GenericResponse.from_dict(res or {}) + + async def delete_webhook(self, req: t.WebhookRequest) -> t.GenericResponse: + """Destructive: permanently deletes the webhook.""" + res = await self._invoke("delete_webhook", d.ADMIN["delete_webhook"], req.to_dict()) + return t.GenericResponse.from_dict(res or {}) + + async def get_webhook(self, req: t.WebhookRequest) -> t.Webhook: + res = await self._invoke("get_webhook", d.ADMIN["get_webhook"], req.to_dict()) + return t.Webhook.from_dict(res or {}) + + async def webhooks(self, req: t.PaginatedRequest | None = None) -> t.WebhooksResponse: + res = await self._invoke("webhooks", d.ADMIN["webhooks"], req.to_dict() if req else None) + return t.WebhooksResponse.from_dict(res or {}) + + async def webhook_logs( + self, req: t.ListWebhookLogRequest | None = None + ) -> t.WebhookLogsResponse: + res = await self._invoke( + "webhook_logs", d.ADMIN["webhook_logs"], req.to_dict() if req else None + ) + return t.WebhookLogsResponse.from_dict(res or {}) + + async def test_endpoint(self, req: t.TestEndpointRequest) -> t.TestEndpointResponse: + res = await self._invoke("test_endpoint", d.ADMIN["test_endpoint"], req.to_dict()) + return t.TestEndpointResponse.from_dict(res or {}) + + # -- email templates -------------------------------------------------- # + async def add_email_template(self, req: t.AddEmailTemplateRequest) -> t.GenericResponse: + res = await self._invoke("add_email_template", d.ADMIN["add_email_template"], req.to_dict()) + return t.GenericResponse.from_dict(res or {}) + + async def update_email_template(self, req: t.UpdateEmailTemplateRequest) -> t.GenericResponse: + res = await self._invoke( + "update_email_template", d.ADMIN["update_email_template"], req.to_dict() + ) + return t.GenericResponse.from_dict(res or {}) + + async def delete_email_template(self, req: t.DeleteEmailTemplateRequest) -> t.GenericResponse: + """Destructive: permanently deletes the email template.""" + res = await self._invoke( + "delete_email_template", d.ADMIN["delete_email_template"], req.to_dict() + ) + return t.GenericResponse.from_dict(res or {}) + + async def email_templates( + self, req: t.PaginatedRequest | None = None + ) -> t.EmailTemplatesResponse: + res = await self._invoke( + "email_templates", d.ADMIN["email_templates"], req.to_dict() if req else None + ) + return t.EmailTemplatesResponse.from_dict(res or {}) + + # -- audit ------------------------------------------------------------ # + async def audit_logs(self, req: t.ListAuditLogRequest | None = None) -> t.AuditLogsResponse: + res = await self._invoke( + "audit_logs", d.ADMIN["audit_logs"], req.to_dict() if req else None + ) + return t.AuditLogsResponse.from_dict(res or {}) + + # -- FGA -------------------------------------------------------------- # + async def fga_get_model(self) -> t.FgaModel: + res = await self._invoke("fga_get_model", d.ADMIN["fga_get_model"], None) + return t.FgaModel.from_dict(res or {}) + + async def fga_write_model(self, req: t.FgaWriteModelRequest) -> t.FgaModel: + """Destructive: replaces the active fine-grained authorization model.""" + res = await self._invoke("fga_write_model", d.ADMIN["fga_write_model"], req.to_dict()) + return t.FgaModel.from_dict(res or {}) + + async def fga_write_tuples(self, req: t.FgaWriteTuplesRequest) -> t.GenericResponse: + res = await self._invoke("fga_write_tuples", d.ADMIN["fga_write_tuples"], req.to_dict()) + return t.GenericResponse.from_dict(res or {}) + + async def fga_delete_tuples(self, req: t.FgaWriteTuplesRequest) -> t.GenericResponse: + """Destructive: removes the given relationship tuples.""" + res = await self._invoke("fga_delete_tuples", d.ADMIN["fga_delete_tuples"], req.to_dict()) + return t.GenericResponse.from_dict(res or {}) + + async def fga_read_tuples(self, req: t.FgaReadTuplesRequest) -> t.FgaReadTuplesResponse: + res = await self._invoke("fga_read_tuples", d.ADMIN["fga_read_tuples"], req.to_dict()) + return t.FgaReadTuplesResponse.from_dict(res or {}) + + async def fga_list_users(self, req: t.FgaListUsersRequest) -> t.FgaListUsersResponse: + res = await self._invoke("fga_list_users", d.ADMIN["fga_list_users"], req.to_dict()) + return t.FgaListUsersResponse.from_dict(res or {}) + + async def fga_expand(self, req: t.FgaExpandRequest) -> t.FgaExpandResponse: + res = await self._invoke("fga_expand", d.ADMIN["fga_expand"], req.to_dict()) + return t.FgaExpandResponse.from_dict(res or {}) + + async def fga_reset(self) -> t.GenericResponse: + """Destructive: deletes the entire fine-grained authorization store.""" + res = await self._invoke("fga_reset", d.ADMIN["fga_reset"], None) + return t.GenericResponse.from_dict(res or {}) diff --git a/src/authorizer/async_client.py b/src/authorizer/async_client.py index cb63731..94c60db 100644 --- a/src/authorizer/async_client.py +++ b/src/authorizer/async_client.py @@ -7,9 +7,10 @@ import httpx -from . import _queries as q +from . import _dispatch as d from . import types as t from ._core import ( + PROTOCOLS, ClientConfig, RequestSpec, build_graphql_request, @@ -18,35 +19,51 @@ parse_graphql_data, parse_graphql_response, parse_oauth_response, + parse_rest, + prepare_http, + unsupported_protocol_error, ) +from ._dispatch import MethodSpec from .exceptions import AuthorizerConnectionError class AsyncAuthorizerClient: """Asynchronous client for an Authorizer instance.""" + _ADMIN = False + def __init__( self, client_id: str, authorizer_url: str, redirect_url: str = "", extra_headers: dict[str, str] | None = None, + protocol: str = "graphql", + grpc_endpoint: str = "", ) -> None: if not client_id or not client_id.strip(): raise ValueError("client_id is required") if not authorizer_url or not authorizer_url.strip(): raise ValueError("authorizer_url is required") + if protocol not in PROTOCOLS: + raise ValueError(f"protocol must be one of {PROTOCOLS}, got {protocol!r}") self._config = ClientConfig( client_id=client_id, authorizer_url=authorizer_url.strip().rstrip("/"), redirect_url=redirect_url.strip().rstrip("/"), extra_headers=dict(extra_headers or {}), + protocol=protocol, + grpc_endpoint=grpc_endpoint.strip(), ) self._http = httpx.AsyncClient() + self._channel: Any = None # -- lifecycle -------------------------------------------------------- # async def aclose(self) -> None: await self._http.aclose() + if self._channel is not None: + await self._channel.close() + self._channel = None async def __aenter__(self) -> AsyncAuthorizerClient: return self @@ -68,19 +85,6 @@ async def _send(self, spec: RequestSpec) -> httpx.Response: except httpx.HTTPError as e: # network/transport failure raise AuthorizerConnectionError(str(e)) from e - async def _graphql( - self, - query: str, - field_name: str, - variables: dict[str, Any] | None = None, - headers: dict[str, str] | None = None, - ) -> dict[str, Any] | None: - spec = build_graphql_request( - self._config.authorizer_url, query, variables, build_headers(self._config, headers) - ) - res = await self._send(spec) - return parse_graphql_response(res.status_code, res.content, field_name) - async def _oauth(self, path: str, body: dict[str, Any]) -> dict[str, Any]: spec = build_oauth_request( self._config.authorizer_url, path, body, build_headers(self._config, None) @@ -88,37 +92,63 @@ async def _oauth(self, path: str, body: dict[str, Any]) -> dict[str, Any]: res = await self._send(spec) return parse_oauth_response(res.status_code, res.content) + async def _invoke( + self, + method: str, + spec: MethodSpec, + data: dict[str, Any] | None = None, + headers: dict[str, str] | None = None, + ) -> dict[str, Any] | None: + """Dispatch ``method`` over the configured protocol and return a dict.""" + proto = self._config.protocol + if proto not in spec.protocols: + raise unsupported_protocol_error(method, proto, spec.protocols) + if proto == "grpc": + from . import _grpc_transport as g + + if self._channel is None: + self._channel = g.make_async_channel( + self._config.authorizer_url, self._config.grpc_endpoint + ) + md = g.grpc_metadata(self._config, headers) + return await g.grpc_acall(self._channel, spec, data, md, self._ADMIN) + req, kind, unwrap = prepare_http(self._config, spec, data, headers) + res = await self._send(req) + if kind == "rest": + return parse_rest(spec, res.status_code, res.content, unwrap, self._ADMIN) + return parse_graphql_response(res.status_code, res.content, unwrap or "") + # -- public auth flows ----------------------------------------------- # async def login(self, req: t.LoginRequest) -> t.AuthToken: - res = await self._graphql(q.LOGIN, "login", {"data": req.to_dict()}) + res = await self._invoke("login", d.PUBLIC["login"], req.to_dict()) return t.AuthToken.from_dict(res or {}) async def signup(self, req: t.SignUpRequest) -> t.AuthToken: - res = await self._graphql(q.SIGNUP, "signup", {"data": req.to_dict()}) + res = await self._invoke("signup", d.PUBLIC["signup"], req.to_dict()) return t.AuthToken.from_dict(res or {}) async def magic_link_login(self, req: t.MagicLinkLoginRequest) -> t.GenericResponse: payload = req.to_dict() if not payload.get("redirect_uri") and self._config.redirect_url: payload["redirect_uri"] = self._config.redirect_url - res = await self._graphql(q.MAGIC_LINK_LOGIN, "magic_link_login", {"data": payload}) + res = await self._invoke("magic_link_login", d.PUBLIC["magic_link_login"], payload) return t.GenericResponse.from_dict(res or {}) async def verify_otp(self, req: t.VerifyOTPRequest) -> t.AuthToken: - res = await self._graphql(q.VERIFY_OTP, "verify_otp", {"data": req.to_dict()}) + res = await self._invoke("verify_otp", d.PUBLIC["verify_otp"], req.to_dict()) return t.AuthToken.from_dict(res or {}) async def verify_email(self, req: t.VerifyEmailRequest) -> t.AuthToken: - res = await self._graphql(q.VERIFY_EMAIL, "verify_email", {"data": req.to_dict()}) + res = await self._invoke("verify_email", d.PUBLIC["verify_email"], req.to_dict()) return t.AuthToken.from_dict(res or {}) async def resend_otp(self, req: t.ResendOTPRequest) -> t.GenericResponse: - res = await self._graphql(q.RESEND_OTP, "resend_otp", {"data": req.to_dict()}) + res = await self._invoke("resend_otp", d.PUBLIC["resend_otp"], req.to_dict()) return t.GenericResponse.from_dict(res or {}) async def resend_verify_email(self, req: t.ResendVerifyEmailRequest) -> t.GenericResponse: - res = await self._graphql( - q.RESEND_VERIFY_EMAIL, "resend_verify_email", {"data": req.to_dict()} + res = await self._invoke( + "resend_verify_email", d.PUBLIC["resend_verify_email"], req.to_dict() ) return t.GenericResponse.from_dict(res or {}) @@ -126,72 +156,72 @@ async def forgot_password(self, req: t.ForgotPasswordRequest) -> t.ForgotPasswor payload = req.to_dict() if not payload.get("redirect_uri") and self._config.redirect_url: payload["redirect_uri"] = self._config.redirect_url - res = await self._graphql(q.FORGOT_PASSWORD, "forgot_password", {"data": payload}) + res = await self._invoke("forgot_password", d.PUBLIC["forgot_password"], payload) return t.ForgotPasswordResponse.from_dict(res or {}) async def reset_password(self, req: t.ResetPasswordRequest) -> t.GenericResponse: - res = await self._graphql(q.RESET_PASSWORD, "reset_password", {"data": req.to_dict()}) + res = await self._invoke("reset_password", d.PUBLIC["reset_password"], req.to_dict()) return t.GenericResponse.from_dict(res or {}) async def validate_jwt_token( self, req: t.ValidateJWTTokenRequest ) -> t.ValidateJWTTokenResponse: - res = await self._graphql( - q.VALIDATE_JWT_TOKEN, "validate_jwt_token", {"data": req.to_dict()} + res = await self._invoke( + "validate_jwt_token", d.PUBLIC["validate_jwt_token"], req.to_dict() ) return t.ValidateJWTTokenResponse.from_dict(res or {}) async def validate_session(self, req: t.ValidateSessionRequest) -> t.ValidateSessionResponse: - res = await self._graphql( - q.VALIDATE_SESSION, "validate_session", {"data": req.to_dict()} - ) + res = await self._invoke("validate_session", d.PUBLIC["validate_session"], req.to_dict()) return t.ValidateSessionResponse.from_dict(res or {}) async def get_meta_data(self) -> t.MetaData: - res = await self._graphql(q.META, "meta") + res = await self._invoke("meta", d.PUBLIC["meta"], None) return t.MetaData.from_dict(res or {}) # -- authenticated (credential headers) ------------------------------ # async def get_session( self, req: t.SessionQueryRequest | None = None, headers: dict[str, str] | None = None ) -> t.AuthToken: - variables = {"data": req.to_dict()} if req is not None else None - res = await self._graphql(q.SESSION, "session", variables, headers) + data = req.to_dict() if req is not None else None + res = await self._invoke("session", d.PUBLIC["session"], data, headers) return t.AuthToken.from_dict(res or {}) async def get_profile(self, headers: dict[str, str] | None = None) -> t.User: - res = await self._graphql(q.PROFILE, "profile", None, headers) + res = await self._invoke("profile", d.PUBLIC["profile"], None, headers) return t.User.from_dict(res or {}) async def update_profile( self, req: t.UpdateProfileRequest, headers: dict[str, str] | None = None ) -> t.GenericResponse: - res = await self._graphql( - q.UPDATE_PROFILE, "update_profile", {"data": req.to_dict()}, headers + res = await self._invoke( + "update_profile", d.PUBLIC["update_profile"], req.to_dict(), headers ) return t.GenericResponse.from_dict(res or {}) async def logout(self, headers: dict[str, str] | None = None) -> t.GenericResponse: - res = await self._graphql(q.LOGOUT, "logout", None, headers) + res = await self._invoke("logout", d.PUBLIC["logout"], None, headers) return t.GenericResponse.from_dict(res or {}) async def deactivate_account(self, headers: dict[str, str] | None = None) -> t.GenericResponse: - res = await self._graphql(q.DEACTIVATE_ACCOUNT, "deactivate_account", None, headers) + res = await self._invoke( + "deactivate_account", d.PUBLIC["deactivate_account"], None, headers + ) return t.GenericResponse.from_dict(res or {}) async def check_permissions( self, req: t.CheckPermissionsRequest, headers: dict[str, str] | None = None ) -> t.CheckPermissionsResponse: - res = await self._graphql( - q.CHECK_PERMISSIONS, "check_permissions", {"data": req.to_dict()}, headers + res = await self._invoke( + "check_permissions", d.PUBLIC["check_permissions"], req.to_dict(), headers ) return t.CheckPermissionsResponse.from_dict(res or {}) async def list_permissions( self, req: t.ListPermissionsRequest, headers: dict[str, str] | None = None ) -> t.ListPermissionsResponse: - res = await self._graphql( - q.LIST_PERMISSIONS, "list_permissions", {"data": req.to_dict()}, headers + res = await self._invoke( + "list_permissions", d.PUBLIC["list_permissions"], req.to_dict(), headers ) return t.ListPermissionsResponse.from_dict(res or {}) diff --git a/src/authorizer/client.py b/src/authorizer/client.py index 9d203e0..aeb7a4a 100644 --- a/src/authorizer/client.py +++ b/src/authorizer/client.py @@ -7,9 +7,10 @@ import httpx -from . import _queries as q +from . import _dispatch as d from . import types as t from ._core import ( + PROTOCOLS, ClientConfig, RequestSpec, build_graphql_request, @@ -18,35 +19,51 @@ parse_graphql_data, parse_graphql_response, parse_oauth_response, + parse_rest, + prepare_http, + unsupported_protocol_error, ) +from ._dispatch import MethodSpec from .exceptions import AuthorizerConnectionError class AuthorizerClient: """Synchronous client for an Authorizer instance.""" + _ADMIN = False + def __init__( self, client_id: str, authorizer_url: str, redirect_url: str = "", extra_headers: dict[str, str] | None = None, + protocol: str = "graphql", + grpc_endpoint: str = "", ) -> None: if not client_id or not client_id.strip(): raise ValueError("client_id is required") if not authorizer_url or not authorizer_url.strip(): raise ValueError("authorizer_url is required") + if protocol not in PROTOCOLS: + raise ValueError(f"protocol must be one of {PROTOCOLS}, got {protocol!r}") self._config = ClientConfig( client_id=client_id, authorizer_url=authorizer_url.strip().rstrip("/"), redirect_url=redirect_url.strip().rstrip("/"), extra_headers=dict(extra_headers or {}), + protocol=protocol, + grpc_endpoint=grpc_endpoint.strip(), ) self._http = httpx.Client() + self._channel: Any = None # -- lifecycle -------------------------------------------------------- # def close(self) -> None: self._http.close() + if self._channel is not None: + self._channel.close() + self._channel = None def __enter__(self) -> AuthorizerClient: return self @@ -68,19 +85,6 @@ def _send(self, spec: RequestSpec) -> httpx.Response: except httpx.HTTPError as e: # network/transport failure raise AuthorizerConnectionError(str(e)) from e - def _graphql( - self, - query: str, - field_name: str, - variables: dict[str, Any] | None = None, - headers: dict[str, str] | None = None, - ) -> dict[str, Any] | None: - spec = build_graphql_request( - self._config.authorizer_url, query, variables, build_headers(self._config, headers) - ) - res = self._send(spec) - return parse_graphql_response(res.status_code, res.content, field_name) - def _oauth(self, path: str, body: dict[str, Any]) -> dict[str, Any]: spec = build_oauth_request( self._config.authorizer_url, path, body, build_headers(self._config, None) @@ -88,100 +92,126 @@ def _oauth(self, path: str, body: dict[str, Any]) -> dict[str, Any]: res = self._send(spec) return parse_oauth_response(res.status_code, res.content) + def _invoke( + self, + method: str, + spec: MethodSpec, + data: dict[str, Any] | None = None, + headers: dict[str, str] | None = None, + ) -> dict[str, Any] | None: + """Dispatch ``method`` over the configured protocol and return a dict.""" + proto = self._config.protocol + if proto not in spec.protocols: + raise unsupported_protocol_error(method, proto, spec.protocols) + if proto == "grpc": + from . import _grpc_transport as g + + if self._channel is None: + self._channel = g.make_channel( + self._config.authorizer_url, self._config.grpc_endpoint + ) + md = g.grpc_metadata(self._config, headers) + return g.grpc_call(self._channel, spec, data, md, self._ADMIN) + req, kind, unwrap = prepare_http(self._config, spec, data, headers) + res = self._send(req) + if kind == "rest": + return parse_rest(spec, res.status_code, res.content, unwrap, self._ADMIN) + return parse_graphql_response(res.status_code, res.content, unwrap or "") + # -- public auth flows ----------------------------------------------- # def login(self, req: t.LoginRequest) -> t.AuthToken: - res = self._graphql(q.LOGIN, "login", {"data": req.to_dict()}) + res = self._invoke("login", d.PUBLIC["login"], req.to_dict()) return t.AuthToken.from_dict(res or {}) def signup(self, req: t.SignUpRequest) -> t.AuthToken: - res = self._graphql(q.SIGNUP, "signup", {"data": req.to_dict()}) + res = self._invoke("signup", d.PUBLIC["signup"], req.to_dict()) return t.AuthToken.from_dict(res or {}) def magic_link_login(self, req: t.MagicLinkLoginRequest) -> t.GenericResponse: payload = req.to_dict() if not payload.get("redirect_uri") and self._config.redirect_url: payload["redirect_uri"] = self._config.redirect_url - res = self._graphql(q.MAGIC_LINK_LOGIN, "magic_link_login", {"data": payload}) + res = self._invoke("magic_link_login", d.PUBLIC["magic_link_login"], payload) return t.GenericResponse.from_dict(res or {}) def verify_otp(self, req: t.VerifyOTPRequest) -> t.AuthToken: - res = self._graphql(q.VERIFY_OTP, "verify_otp", {"data": req.to_dict()}) + res = self._invoke("verify_otp", d.PUBLIC["verify_otp"], req.to_dict()) return t.AuthToken.from_dict(res or {}) def verify_email(self, req: t.VerifyEmailRequest) -> t.AuthToken: - res = self._graphql(q.VERIFY_EMAIL, "verify_email", {"data": req.to_dict()}) + res = self._invoke("verify_email", d.PUBLIC["verify_email"], req.to_dict()) return t.AuthToken.from_dict(res or {}) def resend_otp(self, req: t.ResendOTPRequest) -> t.GenericResponse: - res = self._graphql(q.RESEND_OTP, "resend_otp", {"data": req.to_dict()}) + res = self._invoke("resend_otp", d.PUBLIC["resend_otp"], req.to_dict()) return t.GenericResponse.from_dict(res or {}) def resend_verify_email(self, req: t.ResendVerifyEmailRequest) -> t.GenericResponse: - res = self._graphql(q.RESEND_VERIFY_EMAIL, "resend_verify_email", {"data": req.to_dict()}) + res = self._invoke("resend_verify_email", d.PUBLIC["resend_verify_email"], req.to_dict()) return t.GenericResponse.from_dict(res or {}) def forgot_password(self, req: t.ForgotPasswordRequest) -> t.ForgotPasswordResponse: payload = req.to_dict() if not payload.get("redirect_uri") and self._config.redirect_url: payload["redirect_uri"] = self._config.redirect_url - res = self._graphql(q.FORGOT_PASSWORD, "forgot_password", {"data": payload}) + res = self._invoke("forgot_password", d.PUBLIC["forgot_password"], payload) return t.ForgotPasswordResponse.from_dict(res or {}) def reset_password(self, req: t.ResetPasswordRequest) -> t.GenericResponse: - res = self._graphql(q.RESET_PASSWORD, "reset_password", {"data": req.to_dict()}) + res = self._invoke("reset_password", d.PUBLIC["reset_password"], req.to_dict()) return t.GenericResponse.from_dict(res or {}) def validate_jwt_token(self, req: t.ValidateJWTTokenRequest) -> t.ValidateJWTTokenResponse: - res = self._graphql(q.VALIDATE_JWT_TOKEN, "validate_jwt_token", {"data": req.to_dict()}) + res = self._invoke("validate_jwt_token", d.PUBLIC["validate_jwt_token"], req.to_dict()) return t.ValidateJWTTokenResponse.from_dict(res or {}) def validate_session(self, req: t.ValidateSessionRequest) -> t.ValidateSessionResponse: - res = self._graphql(q.VALIDATE_SESSION, "validate_session", {"data": req.to_dict()}) + res = self._invoke("validate_session", d.PUBLIC["validate_session"], req.to_dict()) return t.ValidateSessionResponse.from_dict(res or {}) def get_meta_data(self) -> t.MetaData: - res = self._graphql(q.META, "meta") + res = self._invoke("meta", d.PUBLIC["meta"], None) return t.MetaData.from_dict(res or {}) # -- authenticated (credential headers) ------------------------------ # def get_session( self, req: t.SessionQueryRequest | None = None, headers: dict[str, str] | None = None ) -> t.AuthToken: - variables = {"data": req.to_dict()} if req is not None else None - res = self._graphql(q.SESSION, "session", variables, headers) + data = req.to_dict() if req is not None else None + res = self._invoke("session", d.PUBLIC["session"], data, headers) return t.AuthToken.from_dict(res or {}) def get_profile(self, headers: dict[str, str] | None = None) -> t.User: - res = self._graphql(q.PROFILE, "profile", None, headers) + res = self._invoke("profile", d.PUBLIC["profile"], None, headers) return t.User.from_dict(res or {}) def update_profile( self, req: t.UpdateProfileRequest, headers: dict[str, str] | None = None ) -> t.GenericResponse: - res = self._graphql(q.UPDATE_PROFILE, "update_profile", {"data": req.to_dict()}, headers) + res = self._invoke("update_profile", d.PUBLIC["update_profile"], req.to_dict(), headers) return t.GenericResponse.from_dict(res or {}) def logout(self, headers: dict[str, str] | None = None) -> t.GenericResponse: - res = self._graphql(q.LOGOUT, "logout", None, headers) + res = self._invoke("logout", d.PUBLIC["logout"], None, headers) return t.GenericResponse.from_dict(res or {}) def deactivate_account(self, headers: dict[str, str] | None = None) -> t.GenericResponse: - res = self._graphql(q.DEACTIVATE_ACCOUNT, "deactivate_account", None, headers) + res = self._invoke("deactivate_account", d.PUBLIC["deactivate_account"], None, headers) return t.GenericResponse.from_dict(res or {}) def check_permissions( self, req: t.CheckPermissionsRequest, headers: dict[str, str] | None = None ) -> t.CheckPermissionsResponse: - res = self._graphql( - q.CHECK_PERMISSIONS, "check_permissions", {"data": req.to_dict()}, headers + res = self._invoke( + "check_permissions", d.PUBLIC["check_permissions"], req.to_dict(), headers ) return t.CheckPermissionsResponse.from_dict(res or {}) def list_permissions( self, req: t.ListPermissionsRequest, headers: dict[str, str] | None = None ) -> t.ListPermissionsResponse: - res = self._graphql( - q.LIST_PERMISSIONS, "list_permissions", {"data": req.to_dict()}, headers + res = self._invoke( + "list_permissions", d.PUBLIC["list_permissions"], req.to_dict(), headers ) return t.ListPermissionsResponse.from_dict(res or {}) diff --git a/src/authorizer/types.py b/src/authorizer/types.py index 64cf58d..111e77f 100644 --- a/src/authorizer/types.py +++ b/src/authorizer/types.py @@ -428,3 +428,472 @@ def from_dict(cls, data: dict[str, Any]) -> ListPermissionsResponse: permissions=[Permission.from_dict(p) for p in perms if isinstance(p, dict)], truncated=bool(data.get("truncated", False)), ) + + +# --------------------------------------------------------------------------- # +# Admin request types +# --------------------------------------------------------------------------- # +@dataclass +class PaginationRequest(_Request): + page: int | None = None + limit: int | None = None + page_token: str | None = None + + +@dataclass +class PaginatedRequest(_Request): + pagination: PaginationRequest | None = None + + +@dataclass +class AdminLoginRequest(_Request): + admin_secret: str + + +@dataclass +class GetUserRequest(_Request): + id: str | None = None + email: str | None = None + + +@dataclass +class UpdateUserRequest(_Request): + id: str + email: str | None = None + email_verified: bool | None = None + given_name: str | None = None + family_name: str | None = None + middle_name: str | None = None + nickname: str | None = None + gender: str | None = None + birthdate: str | None = None + phone_number: str | None = None + phone_number_verified: bool | None = None + picture: str | None = None + roles: list[str] | None = None + is_multi_factor_auth_enabled: bool | None = None + app_data: dict[str, Any] | None = None + + +@dataclass +class DeleteUserRequest(_Request): + email: str + + +@dataclass +class UpdateAccessRequest(_Request): + user_id: str + + +@dataclass +class InviteMembersRequest(_Request): + emails: list[str] + redirect_uri: str | None = None + + +@dataclass +class AddWebhookRequest(_Request): + event_name: str + endpoint: str + enabled: bool = True + event_description: str | None = None + headers: dict[str, Any] | None = None + + +@dataclass +class UpdateWebhookRequest(_Request): + id: str + event_name: str | None = None + event_description: str | None = None + endpoint: str | None = None + enabled: bool | None = None + headers: dict[str, Any] | None = None + + +@dataclass +class WebhookRequest(_Request): + id: str + + +@dataclass +class ListWebhookLogRequest(_Request): + pagination: PaginationRequest | None = None + webhook_id: str | None = None + + +@dataclass +class TestEndpointRequest(_Request): + endpoint: str + event_name: str + event_description: str | None = None + headers: dict[str, Any] | None = None + + +@dataclass +class AddEmailTemplateRequest(_Request): + event_name: str + subject: str + template: str + design: str | None = None + + +@dataclass +class UpdateEmailTemplateRequest(_Request): + id: str + event_name: str | None = None + template: str | None = None + subject: str | None = None + design: str | None = None + + +@dataclass +class DeleteEmailTemplateRequest(_Request): + id: str + + +@dataclass +class ListAuditLogRequest(_Request): + pagination: PaginationRequest | None = None + action: str | None = None + actor_id: str | None = None + resource_type: str | None = None + resource_id: str | None = None + from_timestamp: int | None = None + to_timestamp: int | None = None + + +@dataclass +class AdminSignupRequest(_Request): + admin_secret: str + + +@dataclass +class GenerateJWTKeysRequest(_Request): + type: str + + +@dataclass +class FgaWriteModelRequest(_Request): + dsl: str + + +@dataclass +class FgaWriteTuplesRequest(_Request): + tuples: list[FgaTupleInput] + + +@dataclass +class FgaReadTuplesRequest(_Request): + user: str | None = None + relation: str | None = None + object: str | None = None + page_size: int | None = None + continuation_token: str | None = None + + +@dataclass +class FgaListUsersRequest(_Request): + object: str + relation: str + user_type: str + + +@dataclass +class FgaExpandRequest(_Request): + relation: str + object: str + + +# --------------------------------------------------------------------------- # +# Admin response types +# --------------------------------------------------------------------------- # +@dataclass +class Pagination: + limit: int = 0 + page: int = 0 + offset: int = 0 + total: int = 0 + next_page_token: str | None = None + + @classmethod + def from_dict(cls, data: dict[str, Any]) -> Pagination: + return cls(**_known(cls, data)) + + +def _pagination(data: dict[str, Any]) -> Pagination: + raw = data.get("pagination") + return Pagination.from_dict(raw) if isinstance(raw, dict) else Pagination() + + +def _users(data: dict[str, Any], key: str) -> list[User]: + raw = data.get(key) + items = raw if isinstance(raw, list) else [] + return [User.from_dict(u) for u in items if isinstance(u, dict)] + + +@dataclass +class AdminMeta: + roles: list[str] = field(default_factory=list) + default_roles: list[str] = field(default_factory=list) + protected_roles: list[str] = field(default_factory=list) + + @classmethod + def from_dict(cls, data: dict[str, Any]) -> AdminMeta: + return cls(**_known(cls, data)) + + +@dataclass +class UsersResponse: + users: list[User] = field(default_factory=list) + pagination: Pagination = field(default_factory=Pagination) + + @classmethod + def from_dict(cls, data: dict[str, Any]) -> UsersResponse: + return cls(users=_users(data, "users"), pagination=_pagination(data)) + + +@dataclass +class VerificationRequest: + id: str = "" + identifier: str | None = None + token: str | None = None + email: str | None = None + expires: int | None = None + created_at: int | None = None + updated_at: int | None = None + nonce: str | None = None + redirect_uri: str | None = None + + @classmethod + def from_dict(cls, data: dict[str, Any]) -> VerificationRequest: + return cls(**_known(cls, data)) + + +@dataclass +class VerificationRequestsResponse: + verification_requests: list[VerificationRequest] = field(default_factory=list) + pagination: Pagination = field(default_factory=Pagination) + + @classmethod + def from_dict(cls, data: dict[str, Any]) -> VerificationRequestsResponse: + raw = data.get("verification_requests") + items = raw if isinstance(raw, list) else [] + return cls( + verification_requests=[ + VerificationRequest.from_dict(v) for v in items if isinstance(v, dict) + ], + pagination=_pagination(data), + ) + + +@dataclass +class InviteMembersResponse: + message: str = "" + users: list[User] = field(default_factory=list) + + @classmethod + def from_dict(cls, data: dict[str, Any]) -> InviteMembersResponse: + # GraphQL returns `Users` (capitalized); REST/grpc return `users`. + key = "Users" if "Users" in data else "users" + return cls(message=str(data.get("message", "")), users=_users(data, key)) + + +@dataclass +class Webhook: + id: str = "" + event_name: str | None = None + event_description: str | None = None + endpoint: str | None = None + enabled: bool | None = None + headers: dict[str, Any] | None = None + created_at: int | None = None + updated_at: int | None = None + + @classmethod + def from_dict(cls, data: dict[str, Any]) -> Webhook: + return cls(**_known(cls, data)) + + +@dataclass +class WebhooksResponse: + webhooks: list[Webhook] = field(default_factory=list) + pagination: Pagination = field(default_factory=Pagination) + + @classmethod + def from_dict(cls, data: dict[str, Any]) -> WebhooksResponse: + raw = data.get("webhooks") + items = raw if isinstance(raw, list) else [] + return cls( + webhooks=[Webhook.from_dict(w) for w in items if isinstance(w, dict)], + pagination=_pagination(data), + ) + + +@dataclass +class WebhookLog: + id: str = "" + http_status: int | None = None + response: str | None = None + request: str | None = None + webhook_id: str | None = None + created_at: int | None = None + updated_at: int | None = None + + @classmethod + def from_dict(cls, data: dict[str, Any]) -> WebhookLog: + return cls(**_known(cls, data)) + + +@dataclass +class WebhookLogsResponse: + webhook_logs: list[WebhookLog] = field(default_factory=list) + pagination: Pagination = field(default_factory=Pagination) + + @classmethod + def from_dict(cls, data: dict[str, Any]) -> WebhookLogsResponse: + raw = data.get("webhook_logs") + items = raw if isinstance(raw, list) else [] + return cls( + webhook_logs=[WebhookLog.from_dict(w) for w in items if isinstance(w, dict)], + pagination=_pagination(data), + ) + + +@dataclass +class TestEndpointResponse: + http_status: int | None = None + response: str | None = None + + @classmethod + def from_dict(cls, data: dict[str, Any]) -> TestEndpointResponse: + return cls(**_known(cls, data)) + + +@dataclass +class EmailTemplate: + id: str = "" + event_name: str | None = None + template: str | None = None + design: str | None = None + subject: str | None = None + created_at: int | None = None + updated_at: int | None = None + + @classmethod + def from_dict(cls, data: dict[str, Any]) -> EmailTemplate: + return cls(**_known(cls, data)) + + +@dataclass +class EmailTemplatesResponse: + email_templates: list[EmailTemplate] = field(default_factory=list) + pagination: Pagination = field(default_factory=Pagination) + + @classmethod + def from_dict(cls, data: dict[str, Any]) -> EmailTemplatesResponse: + raw = data.get("email_templates") + items = raw if isinstance(raw, list) else [] + return cls( + email_templates=[EmailTemplate.from_dict(e) for e in items if isinstance(e, dict)], + pagination=_pagination(data), + ) + + +@dataclass +class AuditLog: + id: str = "" + actor_id: str | None = None + actor_type: str | None = None + actor_email: str | None = None + action: str | None = None + resource_type: str | None = None + resource_id: str | None = None + ip_address: str | None = None + user_agent: str | None = None + metadata: str | None = None + created_at: int | None = None + + @classmethod + def from_dict(cls, data: dict[str, Any]) -> AuditLog: + return cls(**_known(cls, data)) + + +@dataclass +class AuditLogsResponse: + audit_logs: list[AuditLog] = field(default_factory=list) + pagination: Pagination = field(default_factory=Pagination) + + @classmethod + def from_dict(cls, data: dict[str, Any]) -> AuditLogsResponse: + raw = data.get("audit_logs") + items = raw if isinstance(raw, list) else [] + return cls( + audit_logs=[AuditLog.from_dict(a) for a in items if isinstance(a, dict)], + pagination=_pagination(data), + ) + + +@dataclass +class GenerateJWTKeysResponse: + secret: str | None = None + public_key: str | None = None + private_key: str | None = None + + @classmethod + def from_dict(cls, data: dict[str, Any]) -> GenerateJWTKeysResponse: + return cls(**_known(cls, data)) + + +@dataclass +class FgaModel: + id: str = "" + dsl: str = "" + + @classmethod + def from_dict(cls, data: dict[str, Any]) -> FgaModel: + return cls(**_known(cls, data)) + + +@dataclass +class FgaTuple: + user: str = "" + relation: str = "" + object: str = "" + + @classmethod + def from_dict(cls, data: dict[str, Any]) -> FgaTuple: + return cls(**_known(cls, data)) + + +@dataclass +class FgaReadTuplesResponse: + tuples: list[FgaTuple] = field(default_factory=list) + continuation_token: str | None = None + + @classmethod + def from_dict(cls, data: dict[str, Any]) -> FgaReadTuplesResponse: + raw = data.get("tuples") + items = raw if isinstance(raw, list) else [] + return cls( + tuples=[FgaTuple.from_dict(x) for x in items if isinstance(x, dict)], + continuation_token=data.get("continuation_token"), + ) + + +@dataclass +class FgaListUsersResponse: + users: list[str] = field(default_factory=list) + + @classmethod + def from_dict(cls, data: dict[str, Any]) -> FgaListUsersResponse: + raw = data.get("users") + return cls(users=list(raw) if isinstance(raw, list) else []) + + +@dataclass +class FgaExpandResponse: + tree: str = "" + + @classmethod + def from_dict(cls, data: dict[str, Any]) -> FgaExpandResponse: + return cls(tree=str(data.get("tree", ""))) diff --git a/tests/integration/__init__.py b/tests/integration/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/integration/test_live.py b/tests/integration/test_live.py new file mode 100644 index 0000000..b103cd9 --- /dev/null +++ b/tests/integration/test_live.py @@ -0,0 +1,464 @@ +"""Live integration tests against a real Authorizer server. + +Gated behind ``@pytest.mark.live`` so it never runs in the default unit suite. +Run against ``lakhansamani/authorizer:2.3.0`` (see SDK_ADMIN_SPEC.md): + + docker run -p 8090:8080 -p 9091:9091 lakhansamani/authorizer:2.3.0 \\ + --database-type=sqlite --database-url=test.db --jwt-type=HS256 \\ + --jwt-secret=test --admin-secret=admin --client-id=test-client \\ + --client-secret=secret + + AUTHORIZER_TEST_URL=http://localhost:8090 \\ + AUTHORIZER_TEST_GRPC=localhost:9091 \\ + AUTHORIZER_TEST_CLIENT_ID=test-client \\ + AUTHORIZER_ADMIN_SECRET=admin \\ + AUTHORIZER_PROTOCOLS=graphql,rest,grpc \\ + pytest tests/integration -m live -v + +Every public method is exercised over EVERY protocol (graphql/rest/grpc) on both +the sync and async clients. As of 2.3.0 (PR #635 + #636) there are no +graphql-only public methods: all 20 public RPCs work over all three protocols and +the response envelope is flat (AuthResponse/User/Meta returned directly). +""" + +from __future__ import annotations + +import asyncio +import os +import time +import uuid + +import httpx +import pytest + +from authorizer import types as t +from authorizer.admin_client import AuthorizerAdminClient +from authorizer.async_admin_client import AsyncAuthorizerAdminClient +from authorizer.async_client import AsyncAuthorizerClient +from authorizer.client import AuthorizerClient +from authorizer.exceptions import AuthorizerError + +pytestmark = pytest.mark.live + + +def _env(*names: str, default: str = "") -> str: + for n in names: + v = os.environ.get(n) + if v: + return v + return default + + +URL = _env("AUTHORIZER_TEST_URL", "AUTHORIZER_URL", default="http://localhost:8091") +GRPC = _env("AUTHORIZER_TEST_GRPC", "AUTHORIZER_GRPC", default="localhost:9092") +CLIENT_ID = _env("AUTHORIZER_TEST_CLIENT_ID", "AUTHORIZER_CLIENT_ID", default="test-client") +ADMIN_SECRET = _env("AUTHORIZER_ADMIN_SECRET", default="admin") +PROTOCOLS = _env("AUTHORIZER_PROTOCOLS", default="graphql,rest,grpc").split(",") +PROTOCOLS = [p.strip() for p in PROTOCOLS if p.strip()] + +PASSWORD = "Test@12345" + + +def _unique(prefix: str) -> str: + return f"{prefix}-{uuid.uuid4().hex[:10]}" + + +# --------------------------------------------------------------------------- # +# Fixtures +# --------------------------------------------------------------------------- # +@pytest.fixture(scope="session", autouse=True) +def _retry_429() -> None: + """Retry HTTP 429s with backoff for the whole session. + + The full matrix (3 protocols x sync+async x many methods) trips the server's + request rate limiter; this is a harness throughput artifact, not an SDK bug. + We wrap httpx's request methods (the SDK transport) to retry transparently. + """ + sync_orig = httpx.Client.request + async_orig = httpx.AsyncClient.request + + def sync_request(self, *args, **kwargs): # type: ignore[no-untyped-def] + for attempt in range(8): + resp = sync_orig(self, *args, **kwargs) + if resp.status_code != 429: + return resp + time.sleep(0.25 * (attempt + 1)) + return resp + + async def async_request(self, *args, **kwargs): # type: ignore[no-untyped-def] + for attempt in range(8): + resp = await async_orig(self, *args, **kwargs) + if resp.status_code != 429: + return resp + await asyncio.sleep(0.25 * (attempt + 1)) + return resp + + httpx.Client.request = sync_request # type: ignore[method-assign,assignment] + httpx.AsyncClient.request = async_request # type: ignore[method-assign,assignment] + yield + httpx.Client.request = sync_orig # type: ignore[method-assign] + httpx.AsyncClient.request = async_orig # type: ignore[method-assign] + + +@pytest.fixture(params=PROTOCOLS) +def protocol(request: pytest.FixtureRequest) -> str: + return str(request.param) + + +@pytest.fixture +def client(protocol: str) -> AuthorizerClient: + c = AuthorizerClient(CLIENT_ID, URL, protocol=protocol, grpc_endpoint=GRPC) + yield c + c.close() + + +@pytest.fixture +def admin(protocol: str) -> AuthorizerAdminClient: + c = AuthorizerAdminClient(URL, ADMIN_SECRET, protocol=protocol, grpc_endpoint=GRPC) + yield c + c.close() + + +def _signup(client: AuthorizerClient) -> tuple[t.AuthToken, dict[str, str], str]: + """Signup a fresh user over graphql and return (auth, bearer_header, session_cookie). + + Graphql signup is always available and sets the session cookie on its httpx + client; we surface that cookie so cookie-bound endpoints (session, + validate_session) can be exercised over every protocol. + """ + gql = AuthorizerClient(CLIENT_ID, URL, protocol="graphql") + try: + auth = gql.signup( + t.SignUpRequest( + email=f"{_unique('py-live')}@example.com", + password=PASSWORD, + confirm_password=PASSWORD, + ) + ) + cookie = gql._http.cookies.get("cookie_session") or "" + finally: + gql.close() + headers = {"Authorization": f"Bearer {auth.access_token}"} if auth.access_token else {} + return auth, headers, cookie + + +# --------------------------------------------------------------------------- # +# Public client — methods available over ALL protocols (sync) +# --------------------------------------------------------------------------- # +def test_meta(client: AuthorizerClient) -> None: + meta = client.get_meta_data() + assert meta.version # populated payload over graphql/rest/grpc + assert meta.is_basic_authentication_enabled is True + + +def test_signup_and_profile(client: AuthorizerClient) -> None: + email = f"{_unique('py-live')}@example.com" + auth = client.signup( + t.SignUpRequest(email=email, password=PASSWORD, confirm_password=PASSWORD) + ) + assert auth.access_token + assert auth.user is not None and auth.user.email == email + headers = {"Authorization": f"Bearer {auth.access_token}"} + profile = client.get_profile(headers=headers) + assert profile.email == email + + +def test_get_session(client: AuthorizerClient) -> None: + _, _, cookie = _signup(client) + # session is cookie-bound: HTTP reads the Cookie header, grpc lowercases it + # to the ``cookie`` metadata key (both accepted by the server). + session = client.get_session(headers={"Cookie": f"cookie_session={cookie}"}) + assert session.access_token # populated AuthToken over all protocols + + +def test_validate_jwt_token(client: AuthorizerClient) -> None: + auth, _, _ = _signup(client) + res = client.validate_jwt_token( + t.ValidateJWTTokenRequest(token=auth.access_token or "", token_type="access_token") + ) + assert res.is_valid is True + + +def test_validate_session(client: AuthorizerClient) -> None: + _, _, cookie = _signup(client) + res = client.validate_session(t.ValidateSessionRequest(cookie=cookie)) + assert res.is_valid is True + + +def test_logout(client: AuthorizerClient) -> None: + _, headers, _ = _signup(client) + res = client.logout(headers=headers) + assert res is not None # GenericResponse over all protocols + + +def test_check_and_list_permissions(client: AuthorizerClient, fga_seed: None) -> None: + _, headers, _ = _signup(client) + check = client.check_permissions( + t.CheckPermissionsRequest( + checks=[t.PermissionCheckInput(relation="reader", object="document:1")] + ), + headers=headers, + ) + assert isinstance(check.results, list) + listed = client.list_permissions( + t.ListPermissionsRequest(object_type="document"), headers=headers + ) + assert isinstance(listed.objects, list) + + +# --------------------------------------------------------------------------- # +# Public client — formerly gql-only methods now work over ALL protocols (rc.9). +# --------------------------------------------------------------------------- # +def test_login(client: AuthorizerClient) -> None: + # Sign up a fresh user (over the same protocol), then log in with it. + email = f"{_unique('py-login')}@example.com" + client.signup(t.SignUpRequest(email=email, password=PASSWORD, confirm_password=PASSWORD)) + auth = client.login(t.LoginRequest(email=email, password=PASSWORD)) + assert auth.access_token + assert auth.user is not None and auth.user.email == email + + +def test_update_profile(client: AuthorizerClient) -> None: + # update_profile is authenticated: over grpc the bearer is sent as metadata + # (#636 interceptor); over http it is the Authorization header. + email = f"{_unique('py-upd')}@example.com" + auth = client.signup( + t.SignUpRequest(email=email, password=PASSWORD, confirm_password=PASSWORD) + ) + headers = {"Authorization": f"Bearer {auth.access_token}"} + res = client.update_profile(t.UpdateProfileRequest(given_name="Updated"), headers=headers) + assert res is not None # GenericResponse over all protocols + prof = client.get_profile(headers=headers) + assert prof.given_name == "Updated" + + +def test_resend_otp_and_forgot_password(client: AuthorizerClient) -> None: + # These hit the server over every protocol now (no gql-only guard). They may + # legitimately error if the feature is disabled server-side; either a flat + # *Response or a clear AuthorizerError is acceptable — what matters is the + # SDK no longer refuses to dispatch them over rest/grpc. + email = f"{_unique('py-otp')}@example.com" + client.signup(t.SignUpRequest(email=email, password=PASSWORD, confirm_password=PASSWORD)) + try: + res = client.forgot_password(t.ForgotPasswordRequest(email=email)) + assert res is not None + except AuthorizerError as e: + assert "not available over" not in str(e) # must reach the server, not refuse + + +# --------------------------------------------------------------------------- # +# Async parity — same public methods over every protocol +# --------------------------------------------------------------------------- # +async def test_async_meta(protocol: str) -> None: + c = AsyncAuthorizerClient(CLIENT_ID, URL, protocol=protocol, grpc_endpoint=GRPC) + try: + meta = await c.get_meta_data() + assert meta.version + finally: + await c.aclose() + + +async def test_async_signup_and_profile(protocol: str) -> None: + c = AsyncAuthorizerClient(CLIENT_ID, URL, protocol=protocol, grpc_endpoint=GRPC) + try: + email = f"{_unique('py-async')}@example.com" + auth = await c.signup( + t.SignUpRequest(email=email, password=PASSWORD, confirm_password=PASSWORD) + ) + assert auth.user is not None and auth.user.email == email + prof = await c.get_profile( + headers={"Authorization": f"Bearer {auth.access_token}"} + ) + assert prof.email == email + finally: + await c.aclose() + + +async def test_async_login_and_update_profile(protocol: str) -> None: + c = AsyncAuthorizerClient(CLIENT_ID, URL, protocol=protocol, grpc_endpoint=GRPC) + try: + email = f"{_unique('py-async-login')}@example.com" + auth = await c.signup( + t.SignUpRequest(email=email, password=PASSWORD, confirm_password=PASSWORD) + ) + logged_in = await c.login(t.LoginRequest(email=email, password=PASSWORD)) + assert logged_in.access_token + headers = {"Authorization": f"Bearer {auth.access_token}"} + res = await c.update_profile( + t.UpdateProfileRequest(family_name="Async"), headers=headers + ) + assert res is not None + finally: + await c.aclose() + + +# --------------------------------------------------------------------------- # +# Admin client — available over all protocols (sync) +# --------------------------------------------------------------------------- # +def test_admin_users(admin: AuthorizerAdminClient) -> None: + page = admin.users(t.PaginatedRequest(pagination=t.PaginationRequest(page=1, limit=10))) + assert page.pagination.page == 1 + assert page.pagination.limit == 10 # int64 string coerced to int over REST + assert isinstance(page.pagination.limit, int) + assert isinstance(page.users, list) + + +def test_admin_verification_requests(admin: AuthorizerAdminClient) -> None: + res = admin.verification_requests( + t.PaginatedRequest(pagination=t.PaginationRequest(page=1, limit=10)) + ) + assert isinstance(res.verification_requests, list) + + +def test_admin_audit_logs(admin: AuthorizerAdminClient) -> None: + res = admin.audit_logs() + assert isinstance(res.audit_logs, list) + + +# Webhook event names are a server-side enum AND carry a UNIQUE constraint, so we +# cannot synthesize a unique name. Instead assign a distinct valid event per +# protocol and clean up (delete) at the end so re-runs do not collide. +_WEBHOOK_EVENTS = { + "graphql": "user.login", + "rest": "user.signup", + "grpc": "user.created", +} + + +def test_admin_webhook_lifecycle(admin: AuthorizerAdminClient, protocol: str) -> None: + event = _WEBHOOK_EVENTS.get(protocol, "user.access_revoked") + endpoint = f"https://example.com/{_unique('hook')}" # host must resolve server-side + created_id = "" + try: + # drop any leftover webhook for this event from an interrupted prior run + for w in admin.webhooks( + t.PaginatedRequest(pagination=t.PaginationRequest(page=1, limit=100)) + ).webhooks: + if w.event_name == event and w.id: + admin.delete_webhook(t.WebhookRequest(id=w.id)) + admin.add_webhook( + t.AddWebhookRequest(event_name=event, endpoint=endpoint, enabled=False) + ) + page = admin.webhooks( + t.PaginatedRequest(pagination=t.PaginationRequest(page=1, limit=100)) + ) + assert isinstance(page.webhooks, list) + match = next((w for w in page.webhooks if w.endpoint == endpoint), None) + assert match is not None and match.id + created_id = match.id + fetched = admin.get_webhook(t.WebhookRequest(id=created_id)) + assert fetched.endpoint == endpoint + finally: + if created_id: + admin.delete_webhook(t.WebhookRequest(id=created_id)) + + +def test_admin_email_template_lifecycle(admin: AuthorizerAdminClient, protocol: str) -> None: + event = "basic_auth_signup" # template event names are an enum; uniqueness via cleanup + created_id = "" + try: + # delete any pre-existing template for this event so the add does not collide + existing = admin.email_templates() + for tmpl in existing.email_templates: + if tmpl.event_name == event and tmpl.id: + admin.delete_email_template(t.DeleteEmailTemplateRequest(id=tmpl.id)) + admin.add_email_template( + t.AddEmailTemplateRequest( + event_name=event, subject=_unique("subj"), template="

hi

" + ) + ) + res = admin.email_templates() + assert isinstance(res.email_templates, list) + match = next((e for e in res.email_templates if e.event_name == event), None) + assert match is not None and match.id + created_id = match.id + finally: + if created_id: + admin.delete_email_template(t.DeleteEmailTemplateRequest(id=created_id)) + + +# -- admin meta / fga get-model (rest + grpc only) --------------------------- # +def test_admin_meta_rest_grpc(protocol: str) -> None: + if protocol == "graphql": + with pytest.raises(AuthorizerError) as exc: + AuthorizerAdminClient(URL, ADMIN_SECRET, protocol="graphql").admin_meta() + assert "not available over graphql" in str(exc.value) + return + c = AuthorizerAdminClient(URL, ADMIN_SECRET, protocol=protocol, grpc_endpoint=GRPC) + try: + assert isinstance(c.admin_meta().roles, list) + finally: + c.close() + + +# --------------------------------------------------------------------------- # +# Async admin parity +# --------------------------------------------------------------------------- # +async def test_async_admin_users(protocol: str) -> None: + c = AsyncAuthorizerAdminClient(URL, ADMIN_SECRET, protocol=protocol, grpc_endpoint=GRPC) + try: + page = await c.users( + t.PaginatedRequest(pagination=t.PaginationRequest(page=1, limit=5)) + ) + assert page.pagination.page == 1 + assert isinstance(page.pagination.limit, int) + finally: + await c.aclose() + + +# --------------------------------------------------------------------------- # +# FGA — model + tuples written once (session), read/list/expand, reset LAST. +# The session-scoped fixture seeds shared state; reset runs exactly once at the +# very end of the session via the autouse teardown. +# --------------------------------------------------------------------------- # +@pytest.fixture(scope="session") +def fga_seed() -> None: + """Write a model + a tuple ONCE for the whole session (idempotent).""" + a = AuthorizerAdminClient(URL, ADMIN_SECRET, protocol="rest", grpc_endpoint=GRPC) + model = ( + "model\n schema 1.1\ntype user\ntype document\n relations\n" + " define reader: [user]\n" + ) + try: + try: + a.fga_write_model(t.FgaWriteModelRequest(dsl=model)) + except AuthorizerError: + pytest.skip("fine-grained authorization not configured") + try: + a.fga_write_tuples( + t.FgaWriteTuplesRequest( + tuples=[ + t.FgaTupleInput(user="user:1", relation="reader", object="document:1") + ] + ) + ) + except AuthorizerError: + pass # tuple already exists from a prior run; fine + finally: + a.close() + return None + + +@pytest.fixture(scope="session", autouse=True) +def _fga_reset_last() -> None: + """Reset the FGA store exactly once, at the very end of the session.""" + yield + a = AuthorizerAdminClient(URL, ADMIN_SECRET, protocol="rest", grpc_endpoint=GRPC) + try: + try: + a.fga_reset() + except AuthorizerError: + pass # not configured / nothing to reset + finally: + a.close() + + +def test_fga_read_list_expand(admin: AuthorizerAdminClient, fga_seed: None) -> None: + reads = admin.fga_read_tuples(t.FgaReadTuplesRequest()) + assert any(x.object == "document:1" for x in reads.tuples) + users = admin.fga_list_users( + t.FgaListUsersRequest(object="document:1", relation="reader", user_type="user") + ) + assert "user:1" in users.users + expand = admin.fga_expand(t.FgaExpandRequest(relation="reader", object="document:1")) + assert expand is not None diff --git a/tests/test_admin_client.py b/tests/test_admin_client.py new file mode 100644 index 0000000..c48a564 --- /dev/null +++ b/tests/test_admin_client.py @@ -0,0 +1,185 @@ +"""Admin client unit tests (graphql + rest), mocked with respx.""" + +from __future__ import annotations + +import pytest +import respx +from httpx import Response + +from authorizer import types as t +from authorizer.admin_client import AuthorizerAdminClient +from authorizer.exceptions import AuthorizerError + +URL = "https://auth.example.com" + + +def _admin(protocol: str = "graphql") -> AuthorizerAdminClient: + return AuthorizerAdminClient(URL, "admin", protocol=protocol) + + +def test_requires_admin_secret() -> None: + with pytest.raises(ValueError): + AuthorizerAdminClient(URL, "") + + +@respx.mock +def test_admin_login_sends_secret_header() -> None: + route = respx.post(f"{URL}/graphql").mock( + return_value=Response(200, json={"data": {"_admin_login": {"message": "ok"}}}) + ) + with _admin() as c: + out = c.admin_login(t.AdminLoginRequest(admin_secret="admin")) + assert out.message == "ok" + assert route.calls[0].request.headers["x-authorizer-admin-secret"] == "admin" + + +@respx.mock +def test_users_graphql_parses_pagination_and_users() -> None: + respx.post(f"{URL}/graphql").mock( + return_value=Response( + 200, + json={ + "data": { + "_users": { + "pagination": {"total": 1, "page": 1, "limit": 10, "offset": 0}, + "users": [{"id": "1", "email": "a@b.com"}], + } + } + }, + ) + ) + with _admin() as c: + out = c.users() + assert out.pagination.total == 1 + assert out.users[0].email == "a@b.com" + + +@respx.mock +def test_user_graphql() -> None: + respx.post(f"{URL}/graphql").mock( + return_value=Response(200, json={"data": {"_user": {"id": "1", "email": "a@b.com"}}}) + ) + with _admin() as c: + assert c.user(t.GetUserRequest(email="a@b.com")).id == "1" + + +@respx.mock +def test_update_user_returns_user() -> None: + respx.post(f"{URL}/graphql").mock( + return_value=Response(200, json={"data": {"_update_user": {"id": "1", "roles": ["admin"]}}}) + ) + with _admin() as c: + out = c.update_user(t.UpdateUserRequest(id="1", roles=["admin"])) + assert out.roles == ["admin"] + + +@respx.mock +def test_delete_user_destructive_message() -> None: + respx.post(f"{URL}/graphql").mock( + return_value=Response(200, json={"data": {"_delete_user": {"message": "deleted"}}}) + ) + with _admin() as c: + assert c.delete_user(t.DeleteUserRequest(email="a@b.com")).message == "deleted" + + +@respx.mock +def test_invite_members_handles_capitalized_users_key() -> None: + respx.post(f"{URL}/graphql").mock( + return_value=Response( + 200, + json={"data": {"_invite_members": {"message": "sent", "Users": [{"id": "9"}]}}}, + ) + ) + with _admin() as c: + out = c.invite_members(t.InviteMembersRequest(emails=["a@b.com"])) + assert out.message == "sent" + assert out.users[0].id == "9" + + +@respx.mock +def test_fga_write_model_returns_model() -> None: + respx.post(f"{URL}/graphql").mock( + return_value=Response( + 200, json={"data": {"_fga_write_model": {"id": "m1", "dsl": "model"}}} + ) + ) + with _admin() as c: + out = c.fga_write_model(t.FgaWriteModelRequest(dsl="model")) + assert out.id == "m1" + + +@respx.mock +def test_fga_read_tuples() -> None: + respx.post(f"{URL}/graphql").mock( + return_value=Response( + 200, + json={ + "data": { + "_fga_read_tuples": { + "tuples": [{"user": "user:1", "relation": "r", "object": "o"}], + "continuation_token": "x", + } + } + }, + ) + ) + with _admin() as c: + out = c.fga_read_tuples(t.FgaReadTuplesRequest()) + assert out.tuples[0].user == "user:1" + assert out.continuation_token == "x" + + +# -- graphql-unsupported methods --------------------------------------------- # +def test_admin_meta_not_available_over_graphql() -> None: + with _admin("graphql") as c: + with pytest.raises(AuthorizerError) as ei: + c.admin_meta() + assert "not available over graphql" in str(ei.value) + + +def test_fga_reset_not_available_over_graphql() -> None: + with _admin("graphql") as c: + with pytest.raises(AuthorizerError): + c.fga_reset() + + +def test_admin_signup_not_available_over_rest() -> None: + with _admin("rest") as c: + with pytest.raises(AuthorizerError) as ei: + c.admin_signup(t.AdminSignupRequest(admin_secret="admin")) + assert "not available over rest" in str(ei.value) + + +# -- REST transport ---------------------------------------------------------- # +@respx.mock +def test_admin_meta_rest_get_and_unwrap() -> None: + route = respx.get(f"{URL}/v1/admin/meta").mock( + return_value=Response(200, json={"admin_meta": {"roles": ["admin"]}}) + ) + with _admin("rest") as c: + out = c.admin_meta() + assert out.roles == ["admin"] + assert route.calls[0].request.headers["x-authorizer-admin-secret"] == "admin" + + +@respx.mock +def test_users_rest_post() -> None: + respx.post(f"{URL}/v1/admin/users").mock( + return_value=Response( + 200, + json={"users": [{"id": "1"}], "pagination": {"total": 1}}, + ) + ) + with _admin("rest") as c: + out = c.users() + assert out.users[0].id == "1" + assert out.pagination.total == 1 + + +@respx.mock +def test_fga_reset_rest() -> None: + respx.post(f"{URL}/v1/admin/fga/reset").mock( + return_value=Response(200, json={"message": "reset"}) + ) + with _admin("rest") as c: + assert c.fga_reset().message == "reset" diff --git a/tests/test_admin_parity.py b/tests/test_admin_parity.py new file mode 100644 index 0000000..10a3d67 --- /dev/null +++ b/tests/test_admin_parity.py @@ -0,0 +1,68 @@ +"""Admin sync/async parity + spec coverage of all 35 admin methods.""" + +from __future__ import annotations + +from authorizer import _dispatch as d +from authorizer.admin_client import AuthorizerAdminClient +from authorizer.async_admin_client import AsyncAuthorizerAdminClient + +# 32 proto RPCs + 3 gql-only extras. +ADMIN_METHODS = [ + "admin_login", + "admin_logout", + "admin_session", + "admin_meta", + "users", + "user", + "update_user", + "delete_user", + "verification_requests", + "revoke_access", + "enable_access", + "invite_members", + "add_webhook", + "update_webhook", + "delete_webhook", + "get_webhook", + "webhooks", + "webhook_logs", + "test_endpoint", + "add_email_template", + "update_email_template", + "delete_email_template", + "email_templates", + "audit_logs", + "fga_get_model", + "fga_write_model", + "fga_write_tuples", + "fga_delete_tuples", + "fga_read_tuples", + "fga_list_users", + "fga_expand", + "fga_reset", + "admin_signup", + "update_env", + "generate_jwt_keys", +] + + +def test_both_admin_clients_expose_same_surface() -> None: + for name in ADMIN_METHODS: + assert hasattr(AuthorizerAdminClient, name), f"sync admin missing {name}" + assert hasattr(AsyncAuthorizerAdminClient, name), f"async admin missing {name}" + + +def test_dispatch_table_covers_every_admin_method() -> None: + assert set(d.ADMIN) == set(ADMIN_METHODS) + assert len(d.ADMIN) == 35 + + +def test_protocol_availability_matches_spec() -> None: + # gql-only extras + for name in ("admin_signup", "update_env", "generate_jwt_keys"): + assert d.ADMIN[name].protocols == ("graphql",) + # rest+grpc only (no graphql op) + for name in ("admin_logout", "admin_session", "admin_meta", "fga_get_model", "fga_reset"): + assert d.ADMIN[name].protocols == ("rest", "grpc") + # full coverage + assert d.ADMIN["users"].protocols == ("graphql", "rest", "grpc") diff --git a/tests/test_protocol_selection.py b/tests/test_protocol_selection.py new file mode 100644 index 0000000..178b882 --- /dev/null +++ b/tests/test_protocol_selection.py @@ -0,0 +1,132 @@ +"""Protocol selection (graphql/rest/grpc) on the public clients.""" + +from __future__ import annotations + +import json + +import pytest +import respx +from httpx import Response + +from authorizer import types as t +from authorizer.async_client import AsyncAuthorizerClient +from authorizer.client import AuthorizerClient +from authorizer.exceptions import AuthorizerError + +URL_GRPC = "http://localhost:8080" + + +def test_invalid_protocol_rejected() -> None: + with pytest.raises(ValueError): + AuthorizerClient("cid", "https://auth.example.com", protocol="soap") + + +@respx.mock +def test_rest_signup_flat_auth_response() -> None: + # rc.9: ALL public RPCs work over rest; the response envelope is FLAT + # (Signup -> AuthResponse), so access_token sits at the top level. + route = respx.post("https://auth.example.com/v1/signup").mock( + return_value=Response(200, json={"access_token": "tok"}) + ) + with AuthorizerClient("cid", "https://auth.example.com", protocol="rest") as c: + out = c.signup(t.SignUpRequest(password="p", email="a@b.com", confirm_password="p")) + assert out.access_token == "tok" + sent = json.loads(route.calls[0].request.content) + assert sent["email"] == "a@b.com" # flat REST body, no graphql wrapping + + +@respx.mock +def test_rest_login_now_supported() -> None: + # rc.9: login (and the other formerly graphql-only methods) work over rest. + respx.post("https://auth.example.com/v1/login").mock( + return_value=Response(200, json={"access_token": "tok"}) + ) + with AuthorizerClient("cid", "https://auth.example.com", protocol="rest") as c: + out = c.login(t.LoginRequest(password="p", email="a@b.com")) + assert out.access_token == "tok" + + +@respx.mock +def test_rest_meta_is_get_and_flat() -> None: + # rc.9: Meta -> Meta (flat), version at the top level. + respx.get("https://auth.example.com/v1/meta").mock( + return_value=Response(200, json={"version": "2.3.0"}) + ) + with AuthorizerClient("cid", "https://auth.example.com", protocol="rest") as c: + assert c.get_meta_data().version == "2.3.0" + + +@respx.mock +def test_rest_message_response_not_unwrapped() -> None: + # logout is available over rest and returns a flat {message} (no wrapper). + respx.post("https://auth.example.com/v1/logout").mock( + return_value=Response(200, json={"message": "logged out"}) + ) + with AuthorizerClient("cid", "https://auth.example.com", protocol="rest") as c: + assert c.logout().message == "logged out" + + +@respx.mock +def test_rest_error_surfaces_message() -> None: + respx.post("https://auth.example.com/v1/signup").mock( + return_value=Response(400, json={"message": "bad creds"}) + ) + with AuthorizerClient("cid", "https://auth.example.com", protocol="rest") as c: + with pytest.raises(AuthorizerError) as ei: + c.signup(t.SignUpRequest(password="p", email="a@b.com", confirm_password="p")) + assert "bad creds" in str(ei.value) + + +@pytest.mark.asyncio +@respx.mock +async def test_async_rest_signup() -> None: + respx.post("https://auth.example.com/v1/signup").mock( + return_value=Response(200, json={"access_token": "tok"}) + ) + async with AsyncAuthorizerClient("cid", "https://auth.example.com", protocol="rest") as c: + out = await c.signup(t.SignUpRequest(password="p", email="a@b.com", confirm_password="p")) + assert out.access_token == "tok" + + +def test_grpc_dispatch_routes_to_transport(monkeypatch: pytest.MonkeyPatch) -> None: + import authorizer._grpc_transport as g + + captured: dict[str, object] = {} + + class FakeChannel: + def close(self) -> None: + captured["closed"] = True + + channel = FakeChannel() + monkeypatch.setattr(g, "make_channel", lambda url, endpoint="": channel) + + def fake_call(ch, spec, data, metadata, admin): # type: ignore[no-untyped-def] + captured.update(channel=ch, method=spec.grpc_method, data=data, admin=admin) + return {"access_token": "tok"} + + monkeypatch.setattr(g, "grpc_call", fake_call) + with AuthorizerClient("cid", URL_GRPC, protocol="grpc") as c: + out = c.signup(t.SignUpRequest(password="p", email="a@b.com", confirm_password="p")) + assert out.access_token == "tok" + assert captured["channel"] is channel + assert captured["closed"] is True + assert captured["method"] == "Signup" + assert captured["admin"] is False + assert captured["data"]["email"] == "a@b.com" # type: ignore[index] + + +def test_grpc_missing_dependency_error(monkeypatch: pytest.MonkeyPatch) -> None: + import builtins + + real_import = builtins.__import__ + + def fake_import(name: str, *args: object, **kwargs: object) -> object: + if name == "grpc": + raise ImportError("no grpc") + return real_import(name, *args, **kwargs) # type: ignore[arg-type] + + monkeypatch.setattr(builtins, "__import__", fake_import) + with AuthorizerClient("cid", "https://auth.example.com", protocol="grpc") as c: + with pytest.raises(AuthorizerError) as ei: + c.signup(t.SignUpRequest(password="p", email="a@b.com", confirm_password="p")) + assert "authorizer-py[grpc]" in str(ei.value)