scalekit-sdk-python 2.19.0__tar.gz → 2.19.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (291) hide show
  1. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/PKG-INFO +1 -1
  2. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/_version.py +1 -1
  3. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/client.py +13 -1
  4. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/core.py +62 -5
  5. scalekit_sdk_python-2.19.1/scalekit/resource.py +96 -0
  6. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit_sdk_python.egg-info/PKG-INFO +1 -1
  7. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit_sdk_python.egg-info/SOURCES.txt +2 -0
  8. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/tests/test_keepalive_channel_options.py +57 -3
  9. scalekit_sdk_python-2.19.1/tests/test_resource.py +81 -0
  10. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/LICENSE +0 -0
  11. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/README.md +0 -0
  12. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/buf/__init__.py +0 -0
  13. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/buf/validate/__init__.py +0 -0
  14. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/buf/validate/validate_pb2.py +0 -0
  15. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/buf/validate/validate_pb2.pyi +0 -0
  16. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/buf/validate/validate_pb2_grpc.py +0 -0
  17. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/pyproject.toml +0 -0
  18. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/__init__.py +0 -0
  19. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/actions/__init__.py +0 -0
  20. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/actions/actions.py +0 -0
  21. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/actions/frameworks/__init__.py +0 -0
  22. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/actions/frameworks/google_adk.py +0 -0
  23. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/actions/frameworks/langchain.py +0 -0
  24. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/actions/frameworks/types/__init__.py +0 -0
  25. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/actions/frameworks/types/google_adk_tool.py +0 -0
  26. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/actions/frameworks/util.py +0 -0
  27. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/actions/models/__init__.py +0 -0
  28. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/actions/models/custom_provider.py +0 -0
  29. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/actions/models/mcp_config.py +0 -0
  30. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/actions/models/mcp_connection_auth_state.py +0 -0
  31. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/actions/models/mcp_instance.py +0 -0
  32. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/actions/models/requests/__init__.py +0 -0
  33. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/actions/models/requests/create_connected_account_request.py +0 -0
  34. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/actions/models/requests/create_custom_provider_request.py +0 -0
  35. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/actions/models/requests/delete_custom_provider_request.py +0 -0
  36. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/actions/models/requests/list_providers_request.py +0 -0
  37. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/actions/models/requests/mcp_request.py +0 -0
  38. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/actions/models/requests/tool_request.py +0 -0
  39. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/actions/models/requests/update_connected_account_request.py +0 -0
  40. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/actions/models/requests/update_custom_provider_request.py +0 -0
  41. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/actions/models/responses/__init__.py +0 -0
  42. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/actions/models/responses/create_connected_account_response.py +0 -0
  43. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/actions/models/responses/create_custom_provider_response.py +0 -0
  44. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/actions/models/responses/create_mcp_config_response.py +0 -0
  45. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/actions/models/responses/create_mcp_response.py +0 -0
  46. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/actions/models/responses/create_mcp_session_token_response.py +0 -0
  47. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/actions/models/responses/delete_connected_account_response.py +0 -0
  48. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/actions/models/responses/delete_custom_provider_response.py +0 -0
  49. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/actions/models/responses/delete_mcp_config_response.py +0 -0
  50. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/actions/models/responses/delete_mcp_instance_response.py +0 -0
  51. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/actions/models/responses/ensure_mcp_instance_response.py +0 -0
  52. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/actions/models/responses/execute_tool_response.py +0 -0
  53. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/actions/models/responses/get_connected_account_auth_response.py +0 -0
  54. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/actions/models/responses/get_mcp_instance_auth_state_response.py +0 -0
  55. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/actions/models/responses/get_mcp_instance_response.py +0 -0
  56. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/actions/models/responses/get_mcp_response.py +0 -0
  57. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/actions/models/responses/list_connected_accounts_response.py +0 -0
  58. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/actions/models/responses/list_mcp_configs_response.py +0 -0
  59. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/actions/models/responses/list_mcp_connected_accounts_response.py +0 -0
  60. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/actions/models/responses/list_mcp_instances_response.py +0 -0
  61. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/actions/models/responses/list_providers_response.py +0 -0
  62. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/actions/models/responses/list_tools_response.py +0 -0
  63. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/actions/models/responses/magic_link_response.py +0 -0
  64. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/actions/models/responses/update_connected_account_response.py +0 -0
  65. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/actions/models/responses/update_custom_provider_response.py +0 -0
  66. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/actions/models/responses/update_mcp_config_response.py +0 -0
  67. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/actions/models/responses/update_mcp_instance_response.py +0 -0
  68. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/actions/models/responses/verify_connected_account_user_response.py +0 -0
  69. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/actions/models/tool_input_output.py +0 -0
  70. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/actions/models/tool_mapping.py +0 -0
  71. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/actions/modifier.py +0 -0
  72. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/actions/types.py +0 -0
  73. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/auth.py +0 -0
  74. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/common/__init__.py +0 -0
  75. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/common/exceptions.py +0 -0
  76. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/common/scalekit.py +0 -0
  77. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/common/user.py +0 -0
  78. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/connected_accounts.py +0 -0
  79. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/connection.py +0 -0
  80. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/constants/__init__.py +0 -0
  81. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/constants/user.py +0 -0
  82. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/directory.py +0 -0
  83. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/domain.py +0 -0
  84. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/events.py +0 -0
  85. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/frameworks/__init__.py +0 -0
  86. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/frameworks/django.py +0 -0
  87. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/frameworks/fastapi.py +0 -0
  88. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/frameworks/flask.py +0 -0
  89. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/m2m_client.py +0 -0
  90. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/mcp.py +0 -0
  91. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/middleware/__init__.py +0 -0
  92. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/middleware/csrf_state.py +0 -0
  93. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/middleware/protocol.py +0 -0
  94. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/middleware/session_crypto.py +0 -0
  95. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/middleware/session_manager.py +0 -0
  96. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/organization.py +0 -0
  97. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/passwordless.py +0 -0
  98. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/permissions.py +0 -0
  99. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/providers.py +0 -0
  100. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/role.py +0 -0
  101. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/sessions.py +0 -0
  102. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/token.py +0 -0
  103. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/tools.py +0 -0
  104. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/users.py +0 -0
  105. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/utils/__init__.py +0 -0
  106. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/utils/directory.py +0 -0
  107. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/v1/__init__.py +0 -0
  108. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/v1/agentkit_logs/__init__.py +0 -0
  109. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/v1/agentkit_logs/agentkit_analytics_pb2.py +0 -0
  110. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/v1/agentkit_logs/agentkit_analytics_pb2.pyi +0 -0
  111. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/v1/agentkit_logs/agentkit_analytics_pb2_grpc.py +0 -0
  112. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/v1/agentkit_logs/agentkit_logs_pb2.py +0 -0
  113. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/v1/agentkit_logs/agentkit_logs_pb2.pyi +0 -0
  114. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/v1/agentkit_logs/agentkit_logs_pb2_grpc.py +0 -0
  115. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/v1/auditlogs/__init__.py +0 -0
  116. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/v1/auditlogs/auditlogs_pb2.py +0 -0
  117. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/v1/auditlogs/auditlogs_pb2.pyi +0 -0
  118. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/v1/auditlogs/auditlogs_pb2_grpc.py +0 -0
  119. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/v1/auth/__init__.py +0 -0
  120. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/v1/auth/auth_pb2.py +0 -0
  121. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/v1/auth/auth_pb2.pyi +0 -0
  122. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/v1/auth/auth_pb2_grpc.py +0 -0
  123. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/v1/auth/passwordless_pb2.py +0 -0
  124. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/v1/auth/passwordless_pb2.pyi +0 -0
  125. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/v1/auth/passwordless_pb2_grpc.py +0 -0
  126. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/v1/auth/totp_pb2.py +0 -0
  127. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/v1/auth/totp_pb2.pyi +0 -0
  128. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/v1/auth/totp_pb2_grpc.py +0 -0
  129. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/v1/auth/webauthn_pb2.py +0 -0
  130. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/v1/auth/webauthn_pb2.pyi +0 -0
  131. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/v1/auth/webauthn_pb2_grpc.py +0 -0
  132. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/v1/billing/__init__.py +0 -0
  133. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/v1/billing/billing_pb2.py +0 -0
  134. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/v1/billing/billing_pb2.pyi +0 -0
  135. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/v1/billing/billing_pb2_grpc.py +0 -0
  136. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/v1/clients/__init__.py +0 -0
  137. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/v1/clients/clients_pb2.py +0 -0
  138. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/v1/clients/clients_pb2.pyi +0 -0
  139. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/v1/clients/clients_pb2_grpc.py +0 -0
  140. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/v1/commons/__init__.py +0 -0
  141. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/v1/commons/commons_pb2.py +0 -0
  142. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/v1/commons/commons_pb2.pyi +0 -0
  143. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/v1/commons/commons_pb2_grpc.py +0 -0
  144. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/v1/connected_accounts/__init__.py +0 -0
  145. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/v1/connected_accounts/connected_accounts_pb2.py +0 -0
  146. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/v1/connected_accounts/connected_accounts_pb2.pyi +0 -0
  147. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/v1/connected_accounts/connected_accounts_pb2_grpc.py +0 -0
  148. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/v1/connections/__init__.py +0 -0
  149. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/v1/connections/connections_pb2.py +0 -0
  150. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/v1/connections/connections_pb2.pyi +0 -0
  151. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/v1/connections/connections_pb2_grpc.py +0 -0
  152. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/v1/directories/__init__.py +0 -0
  153. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/v1/directories/directories_pb2.py +0 -0
  154. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/v1/directories/directories_pb2.pyi +0 -0
  155. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/v1/directories/directories_pb2_grpc.py +0 -0
  156. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/v1/domains/__init__.py +0 -0
  157. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/v1/domains/domains_pb2.py +0 -0
  158. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/v1/domains/domains_pb2.pyi +0 -0
  159. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/v1/domains/domains_pb2_grpc.py +0 -0
  160. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/v1/emails/__init__.py +0 -0
  161. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/v1/emails/emails_pb2.py +0 -0
  162. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/v1/emails/emails_pb2.pyi +0 -0
  163. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/v1/emails/emails_pb2_grpc.py +0 -0
  164. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/v1/environments/__init__.py +0 -0
  165. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/v1/environments/environments_pb2.py +0 -0
  166. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/v1/environments/environments_pb2.pyi +0 -0
  167. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/v1/environments/environments_pb2_grpc.py +0 -0
  168. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/v1/errdetails/__init__.py +0 -0
  169. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/v1/errdetails/errdetails_pb2.py +0 -0
  170. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/v1/errdetails/errdetails_pb2.pyi +0 -0
  171. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/v1/errdetails/errdetails_pb2_grpc.py +0 -0
  172. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/v1/events/__init__.py +0 -0
  173. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/v1/events/events_pb2.py +0 -0
  174. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/v1/events/events_pb2.pyi +0 -0
  175. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/v1/events/events_pb2_grpc.py +0 -0
  176. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/v1/gateway/__init__.py +0 -0
  177. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/v1/gateway/gateway_pb2.py +0 -0
  178. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/v1/gateway/gateway_pb2.pyi +0 -0
  179. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/v1/gateway/gateway_pb2_grpc.py +0 -0
  180. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/v1/interceptors/__init__.py +0 -0
  181. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/v1/interceptors/interceptors_pb2.py +0 -0
  182. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/v1/interceptors/interceptors_pb2.pyi +0 -0
  183. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/v1/interceptors/interceptors_pb2_grpc.py +0 -0
  184. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/v1/keys/__init__.py +0 -0
  185. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/v1/keys/keys_pb2.py +0 -0
  186. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/v1/keys/keys_pb2.pyi +0 -0
  187. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/v1/keys/keys_pb2_grpc.py +0 -0
  188. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/v1/logstreams/__init__.py +0 -0
  189. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/v1/logstreams/logstreams_pb2.py +0 -0
  190. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/v1/logstreams/logstreams_pb2.pyi +0 -0
  191. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/v1/logstreams/logstreams_pb2_grpc.py +0 -0
  192. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/v1/mcp/__init__.py +0 -0
  193. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/v1/mcp/mcp_pb2.py +0 -0
  194. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/v1/mcp/mcp_pb2.pyi +0 -0
  195. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/v1/mcp/mcp_pb2_grpc.py +0 -0
  196. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/v1/members/__init__.py +0 -0
  197. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/v1/members/members_pb2.py +0 -0
  198. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/v1/members/members_pb2.pyi +0 -0
  199. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/v1/members/members_pb2_grpc.py +0 -0
  200. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/v1/migrations/__init__.py +0 -0
  201. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/v1/migrations/migrations_pb2.py +0 -0
  202. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/v1/migrations/migrations_pb2.pyi +0 -0
  203. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/v1/migrations/migrations_pb2_grpc.py +0 -0
  204. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/v1/options/__init__.py +0 -0
  205. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/v1/options/options_pb2.py +0 -0
  206. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/v1/options/options_pb2.pyi +0 -0
  207. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/v1/options/options_pb2_grpc.py +0 -0
  208. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/v1/organizations/__init__.py +0 -0
  209. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/v1/organizations/organizations_pb2.py +0 -0
  210. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/v1/organizations/organizations_pb2.pyi +0 -0
  211. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/v1/organizations/organizations_pb2_grpc.py +0 -0
  212. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/v1/providers/__init__.py +0 -0
  213. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/v1/providers/providers_pb2.py +0 -0
  214. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/v1/providers/providers_pb2.pyi +0 -0
  215. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/v1/providers/providers_pb2_grpc.py +0 -0
  216. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/v1/roles/__init__.py +0 -0
  217. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/v1/roles/roles_pb2.py +0 -0
  218. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/v1/roles/roles_pb2.pyi +0 -0
  219. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/v1/roles/roles_pb2_grpc.py +0 -0
  220. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/v1/secrets/__init__.py +0 -0
  221. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/v1/secrets/secrets_pb2.py +0 -0
  222. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/v1/secrets/secrets_pb2.pyi +0 -0
  223. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/v1/secrets/secrets_pb2_grpc.py +0 -0
  224. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/v1/sessions/__init__.py +0 -0
  225. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/v1/sessions/sessions_pb2.py +0 -0
  226. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/v1/sessions/sessions_pb2.pyi +0 -0
  227. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/v1/sessions/sessions_pb2_grpc.py +0 -0
  228. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/v1/tokens/__init__.py +0 -0
  229. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/v1/tokens/tokens_pb2.py +0 -0
  230. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/v1/tokens/tokens_pb2.pyi +0 -0
  231. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/v1/tokens/tokens_pb2_grpc.py +0 -0
  232. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/v1/tools/__init__.py +0 -0
  233. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/v1/tools/tools_pb2.py +0 -0
  234. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/v1/tools/tools_pb2.pyi +0 -0
  235. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/v1/tools/tools_pb2_grpc.py +0 -0
  236. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/v1/user_attributes/__init__.py +0 -0
  237. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/v1/user_attributes/user_attributes_pb2.py +0 -0
  238. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/v1/user_attributes/user_attributes_pb2.pyi +0 -0
  239. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/v1/user_attributes/user_attributes_pb2_grpc.py +0 -0
  240. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/v1/users/__init__.py +0 -0
  241. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/v1/users/users_pb2.py +0 -0
  242. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/v1/users/users_pb2.pyi +0 -0
  243. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/v1/users/users_pb2_grpc.py +0 -0
  244. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/v1/webhooks/__init__.py +0 -0
  245. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/v1/webhooks/webhooks_pb2.py +0 -0
  246. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/v1/webhooks/webhooks_pb2.pyi +0 -0
  247. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/v1/webhooks/webhooks_pb2_grpc.py +0 -0
  248. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/v1/workspaces/__init__.py +0 -0
  249. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/v1/workspaces/workspaces_pb2.py +0 -0
  250. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/v1/workspaces/workspaces_pb2.pyi +0 -0
  251. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/v1/workspaces/workspaces_pb2_grpc.py +0 -0
  252. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit/webauthn.py +0 -0
  253. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit_sdk_python.egg-info/dependency_links.txt +0 -0
  254. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit_sdk_python.egg-info/requires.txt +0 -0
  255. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/scalekit_sdk_python.egg-info/top_level.txt +0 -0
  256. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/setup.cfg +0 -0
  257. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/setup.py +0 -0
  258. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/tests/test_actions.py +0 -0
  259. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/tests/test_call_timeout.py +0 -0
  260. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/tests/test_connected_accounts.py +0 -0
  261. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/tests/test_connection.py +0 -0
  262. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/tests/test_directory.py +0 -0
  263. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/tests/test_domain.py +0 -0
  264. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/tests/test_events.py +0 -0
  265. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/tests/test_http_timeout.py +0 -0
  266. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/tests/test_login.py +0 -0
  267. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/tests/test_m2m_client.py +0 -0
  268. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/tests/test_mcp.py +0 -0
  269. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/tests/test_middleware_csrf_state.py +0 -0
  270. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/tests/test_middleware_django.py +0 -0
  271. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/tests/test_middleware_fastapi.py +0 -0
  272. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/tests/test_middleware_flask.py +0 -0
  273. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/tests/test_middleware_session_crypto.py +0 -0
  274. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/tests/test_middleware_session_manager.py +0 -0
  275. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/tests/test_org_roles.py +0 -0
  276. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/tests/test_organization.py +0 -0
  277. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/tests/test_organization_session_policy.py +0 -0
  278. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/tests/test_organization_slug_logo.py +0 -0
  279. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/tests/test_passwordless.py +0 -0
  280. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/tests/test_permissions.py +0 -0
  281. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/tests/test_providers.py +0 -0
  282. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/tests/test_role_defaults_dependent.py +0 -0
  283. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/tests/test_roles.py +0 -0
  284. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/tests/test_sessions.py +0 -0
  285. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/tests/test_sk819_retry_behavior.py +0 -0
  286. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/tests/test_tokens.py +0 -0
  287. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/tests/test_tools.py +0 -0
  288. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/tests/test_transient_error_no_retry.py +0 -0
  289. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/tests/test_user_roles_permissions.py +0 -0
  290. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/tests/test_users.py +0 -0
  291. {scalekit_sdk_python-2.19.0 → scalekit_sdk_python-2.19.1}/tests/test_webauthn_credentials.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: scalekit-sdk-python
3
- Version: 2.19.0
3
+ Version: 2.19.1
4
4
  Summary: Scalekit official Python SDK
5
5
  Home-page: https://github.com/scalekit-inc/scalekit-sdk-python
6
6
  Author: Team Scalekit
@@ -1,3 +1,3 @@
1
1
  # Single source of truth for the SDK version.
2
2
  # Import this in setup.py and scalekit/core.py — never hardcode the version elsewhere.
3
- __version__ = "2.19.0"
3
+ __version__ = "2.19.1"
@@ -19,6 +19,7 @@ from scalekit.core import (
19
19
  from scalekit.domain import DomainClient
20
20
  from scalekit.connection import ConnectionClient
21
21
  from scalekit.m2m_client import M2MClient
22
+ from scalekit.resource import ResourceClient
22
23
  from scalekit.organization import OrganizationClient
23
24
  from scalekit.directory import DirectoryClient
24
25
  from scalekit.users import UserClient
@@ -77,9 +78,19 @@ class ScalekitClient:
77
78
  :type : ``` str ```
78
79
  :param keepalive_time_ms : How often, in milliseconds, an idle gRPC
79
80
  connection is verified before reuse.
81
+ Also derives grpc.client_idle_timeout_ms
82
+ (see CLIENT_IDLE_TIMEOUT_CEILING_MS),
83
+ which proactively recycles a connection
84
+ with zero active calls before the
85
+ backend's own MaxConnectionIdle would.
80
86
  Defaults to 60000; most callers never
81
87
  need to set this. Set to 0 to disable
82
- keepalive entirely.
88
+ both of this SDK's own settings for
89
+ these — grpc-core still applies its own
90
+ (much larger) default idle behavior
91
+ when no options are passed at all, so
92
+ this isn't "no idle handling," just no
93
+ SDK-configured one.
83
94
  :type : ``` int ```
84
95
  :param keepalive_timeout_ms : How long, in milliseconds, to wait for a
85
96
  keepalive response before treating an
@@ -122,6 +133,7 @@ class ScalekitClient:
122
133
  self.organization = OrganizationClient(self.core_client)
123
134
  self.directory = DirectoryClient(self.core_client)
124
135
  self.m2m_client = M2MClient(self.core_client)
136
+ self.resources = ResourceClient(self.core_client)
125
137
  self.users = UserClient(self.core_client)
126
138
  self.roles = RoleClient(self.core_client)
127
139
  self.permissions = PermissionClient(self.core_client)
@@ -45,6 +45,32 @@ DEFAULT_KEEPALIVE_TIMEOUT_MS = 10_000
45
45
  # never even reaches the wire as requested.) Reject 1..59999.
46
46
  MIN_KEEPALIVE_TIME_MS = 60_000
47
47
 
48
+ # grpc-core exposes 'grpc.client_idle_timeout_ms' (gRFC A9) as the client-side
49
+ # equivalent of what the Go and Node SDKs implement by hand on their
50
+ # self-managed HTTP/2 transports (grpcIdleConnTimeout / idleConnectionTimeoutMs):
51
+ # proactively transition a fully-idle channel so its connection is torn down
52
+ # and lazily recreated on the next call, instead of waiting to discover it's
53
+ # dead (or waiting for the backend to GOAWAY it) only when a real request is
54
+ # written to it. This SDK previously configured keepalive pings but never this
55
+ # option — the gap this constant and CLIENT_IDLE_TIMEOUT_PING_CYCLES close.
56
+ #
57
+ # Must stay strictly BELOW the backend's own grpcKeepaliveMaxConnectionIdle
58
+ # (5 min, scalekit's cmd/grpc.go), not equal to it: landing exactly on the
59
+ # backend's bound is a race — whichever side's timer fires first wins, and the
60
+ # loser is a request written into a socket the other side just closed. Mirrors
61
+ # the Go SDK's grpcIdleConnCeiling and the Node SDK's
62
+ # IDLE_CONNECTION_TIMEOUT_CEILING_MS exactly (both 4 minutes), for the same
63
+ # reason.
64
+ CLIENT_IDLE_TIMEOUT_CEILING_MS = 240_000
65
+
66
+ # Multiplier applied to keepalive_time_ms before clamping to the ceiling above
67
+ # — mirrors the Go SDK's grpcIdleConnPingCycles / Node SDK's
68
+ # IDLE_PING_CYCLES_BEFORE_CLOSE (both 5) exactly, so this SDK scales down
69
+ # correctly alongside the other two should MIN_KEEPALIVE_TIME_MS itself ever
70
+ # be lowered. Superseded by the ceiling for every currently-valid non-zero
71
+ # keepalive_time_ms (60s x 5 = 300s already exceeds the 4-minute ceiling).
72
+ CLIENT_IDLE_TIMEOUT_PING_CYCLES = 5
73
+
48
74
  # requests defaults to no timeout, so a black-holed connection blocks the
49
75
  # calling thread until the OS abandons the socket. Bound the connect and read
50
76
  # phases separately with a (connect, read) tuple.
@@ -113,6 +139,22 @@ def _assert_valid_timeout(name: str, value) -> None:
113
139
  )
114
140
 
115
141
 
142
+ def _client_idle_timeout_ms_for(keepalive_time_ms: int) -> int:
143
+ """Derive grpc.client_idle_timeout_ms from keepalive_time_ms — mirrors the
144
+ Go SDK's idleConnTimeoutFor / Node SDK's idleConnectionTimeoutMsFor exactly
145
+ (same formula, same constants), so the three SDKs land on the same idle-close
146
+ behavior. keepalive_time_ms == 0 (disabled) returns 0, meaning "not set" to
147
+ the caller (see __grpc_secure_channel — no option is passed, so grpc-core's
148
+ own much larger default applies), consistent with keepalive_time_ms == 0
149
+ disabling the ping-based idle detection above too."""
150
+ if not keepalive_time_ms:
151
+ return 0
152
+ scaled = keepalive_time_ms * CLIENT_IDLE_TIMEOUT_PING_CYCLES
153
+ if scaled <= 0 or scaled > CLIENT_IDLE_TIMEOUT_CEILING_MS:
154
+ return CLIENT_IDLE_TIMEOUT_CEILING_MS
155
+ return scaled
156
+
157
+
116
158
  def _is_success_status(status_code: int) -> bool:
117
159
  """200-only would be a footgun: the token/JWKS endpoints are only ever
118
160
  expected to reply 200, but a strict != 200 check would misclassify any
@@ -171,9 +213,18 @@ class CoreClient:
171
213
  connection is verified before reuse.
172
214
  Must stay above the backend's keepalive
173
215
  MinTime (30s) with real margin, or the
174
- server treats this ping as abuse. Defaults
175
- to 60000. Set to 0 to disable keepalive
176
- entirely.
216
+ server treats this ping as abuse. Also
217
+ derives grpc.client_idle_timeout_ms (see
218
+ CLIENT_IDLE_TIMEOUT_CEILING_MS), which
219
+ proactively recycles a connection with
220
+ zero active calls before the backend's
221
+ own MaxConnectionIdle would. Defaults to
222
+ 60000. Set to 0 to disable both of this
223
+ SDK's own settings for these — grpc-core
224
+ still applies its own (much larger)
225
+ default idle behavior when no options
226
+ are passed at all, so this isn't "no
227
+ idle handling," just no SDK-configured one.
177
228
  :type : ``` int ```
178
229
  :param keepalive_timeout_ms : How long, in milliseconds, to wait for a
179
230
  keepalive response before treating an
@@ -242,8 +293,10 @@ class CoreClient:
242
293
  channel_credentials,
243
294
  call_credentials,
244
295
  )
245
- # keepalive_time_ms == 0 disables keepalive entirely: no options are
246
- # passed, so grpc-core falls back to its own defaults (no idle pings).
296
+ # keepalive_time_ms == 0 disables keepalive (and, below, the derived
297
+ # idle-close timeout) entirely: no options are passed, so grpc-core
298
+ # falls back to its own defaults (no idle pings, ~30 min idle timeout)
299
+ # — an escape hatch for a network path that rejects this pattern.
247
300
  channel_options = []
248
301
  if self.keepalive_time_ms:
249
302
  # keepalive_permit_without_calls=1 so an idle channel is still
@@ -256,6 +309,10 @@ class CoreClient:
256
309
  ('grpc.keepalive_timeout_ms', self.keepalive_timeout_ms),
257
310
  ('grpc.keepalive_permit_without_calls', 1),
258
311
  ('grpc.http2.max_pings_without_data', 0),
312
+ # Proactively idle out (and lazily recreate on next use) a
313
+ # connection with zero active calls before the backend's own
314
+ # MaxConnectionIdle would — see CLIENT_IDLE_TIMEOUT_CEILING_MS.
315
+ ('grpc.client_idle_timeout_ms', _client_idle_timeout_ms_for(self.keepalive_time_ms)),
259
316
  ]
260
317
  self.grpc_secure_channel = grpc.secure_channel(
261
318
  self.host, composite_credentials, options=channel_options
@@ -0,0 +1,96 @@
1
+ from typing import Optional, List
2
+
3
+ from scalekit.core import CoreClient
4
+ from scalekit.v1.clients.clients_pb2 import *
5
+ from scalekit.v1.clients.clients_pb2_grpc import ClientServiceStub
6
+
7
+
8
+ class ResourceClient:
9
+ """API to read and revoke end-user consents granted against a resource"""
10
+
11
+ def __init__(self, core_client: CoreClient):
12
+ """
13
+ Initializer for Resource Client
14
+
15
+ :param core_client : CoreClient Object
16
+ :type : ``` obj ```
17
+ :returns
18
+ None
19
+ """
20
+ self.core_client = core_client
21
+ self.client_service = ClientServiceStub(self.core_client.grpc_secure_channel)
22
+
23
+ def list_user_consents(
24
+ self,
25
+ resource_id: str,
26
+ search: Optional[str] = None,
27
+ page_size: Optional[int] = None,
28
+ page_token: Optional[str] = None,
29
+ user_ids: Optional[List[str]] = None,
30
+ ) -> ListResourceUserConsentsResponse:
31
+ """
32
+ Method to list the end-user consents granted against a resource
33
+
34
+ Each returned consent carries id, external_user_id, client_id, client_name,
35
+ scopes and granted_at. The response also carries total_size plus
36
+ next_page_token / prev_page_token cursors.
37
+
38
+ Pass user_ids to match specific external user IDs exactly and
39
+ case-sensitively. Pass search for a case-insensitive substring match.
40
+ When both are given, user_ids wins and search is ignored.
41
+
42
+ :param resource_id : Resource id to list consents for (format: res_xxxxx)
43
+ :type : ``` str ```
44
+ :param search : Case-insensitive substring match on external user IDs
45
+ :type : ``` str ```
46
+ :param page_size : Page size for pagination (max 30)
47
+ :type : ``` int ```
48
+ :param page_token : Page token for pagination
49
+ :type : ``` str ```
50
+ :param user_ids : Exact match on external user IDs (max 25)
51
+ :type : ``` list ```
52
+ :returns:
53
+ List Resource User Consents Response
54
+ """
55
+ if not resource_id:
56
+ raise ValueError("resource_id is required")
57
+
58
+ return self.core_client.grpc_exec(
59
+ self.client_service.ListResourceUserConsents.with_call,
60
+ ListResourceUserConsentsRequest(
61
+ resource_id=resource_id,
62
+ search=search,
63
+ page_size=page_size,
64
+ page_token=page_token,
65
+ filter=ResourceUserConsentFilter(external_user_id=user_ids) if user_ids else None,
66
+ )
67
+ )
68
+
69
+ def revoke_user_consent(self, client_id: str, consent_id: str) -> RevokeUserConsentResponse:
70
+ """
71
+ Method to revoke a single end-user consent held by an API client
72
+
73
+ Deletes the consent, so the client is prompted for consent again on its next
74
+ authorization attempt, and revokes every active refresh token issued to that
75
+ client for the same user. Access tokens already issued stay valid until they
76
+ expire.
77
+
78
+ Note that client_id is the API client that holds the consent, not the
79
+ resource id.
80
+
81
+ :param client_id : Client holding the consent (format: m2m_xxxxx)
82
+ :type : ``` str ```
83
+ :param consent_id : Consent to revoke (format: usrcnst_xxxxx)
84
+ :type : ``` str ```
85
+ :returns:
86
+ Revoke User Consent Response
87
+ """
88
+ if not client_id:
89
+ raise ValueError("client_id is required")
90
+ if not consent_id:
91
+ raise ValueError("consent_id is required")
92
+
93
+ return self.core_client.grpc_exec(
94
+ self.client_service.RevokeUserConsent.with_call,
95
+ RevokeUserConsentRequest(client_id=client_id, consent_id=consent_id)
96
+ )
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: scalekit-sdk-python
3
- Version: 2.19.0
3
+ Version: 2.19.1
4
4
  Summary: Scalekit official Python SDK
5
5
  Home-page: https://github.com/scalekit-inc/scalekit-sdk-python
6
6
  Author: Team Scalekit
@@ -23,6 +23,7 @@ scalekit/organization.py
23
23
  scalekit/passwordless.py
24
24
  scalekit/permissions.py
25
25
  scalekit/providers.py
26
+ scalekit/resource.py
26
27
  scalekit/role.py
27
28
  scalekit/sessions.py
28
29
  scalekit/token.py
@@ -275,6 +276,7 @@ tests/test_organization_slug_logo.py
275
276
  tests/test_passwordless.py
276
277
  tests/test_permissions.py
277
278
  tests/test_providers.py
279
+ tests/test_resource.py
278
280
  tests/test_role_defaults_dependent.py
279
281
  tests/test_roles.py
280
282
  tests/test_sessions.py
@@ -15,6 +15,9 @@ from scalekit.core import (
15
15
  CoreClient,
16
16
  DEFAULT_KEEPALIVE_TIME_MS,
17
17
  DEFAULT_KEEPALIVE_TIMEOUT_MS,
18
+ CLIENT_IDLE_TIMEOUT_CEILING_MS,
19
+ CLIENT_IDLE_TIMEOUT_PING_CYCLES,
20
+ _client_idle_timeout_ms_for,
18
21
  )
19
22
 
20
23
 
@@ -50,8 +53,8 @@ class TestKeepaliveChannelOptions(unittest.TestCase):
50
53
  _, mock_secure_channel = _build_client(keepalive_time_ms=0)
51
54
  self.assertEqual(self._options_from(mock_secure_channel), [])
52
55
 
53
- def test_default_construction_includes_all_four_options(self):
54
- """Default construction must include all four expected option tuples."""
56
+ def test_default_construction_includes_all_five_options(self):
57
+ """Default construction must include all five expected option tuples."""
55
58
  _, mock_secure_channel = _build_client()
56
59
  options = self._options_from(mock_secure_channel)
57
60
  self.assertEqual(
@@ -61,10 +64,12 @@ class TestKeepaliveChannelOptions(unittest.TestCase):
61
64
  ('grpc.keepalive_timeout_ms', DEFAULT_KEEPALIVE_TIMEOUT_MS),
62
65
  ('grpc.keepalive_permit_without_calls', 1),
63
66
  ('grpc.http2.max_pings_without_data', 0),
67
+ ('grpc.client_idle_timeout_ms', CLIENT_IDLE_TIMEOUT_CEILING_MS),
64
68
  ],
65
69
  )
66
- # Explicit check on the documented default value.
70
+ # Explicit check on the documented default values.
67
71
  self.assertIn(('grpc.keepalive_time_ms', 60000), options)
72
+ self.assertIn(('grpc.client_idle_timeout_ms', 240000), options)
68
73
 
69
74
  def test_below_minimum_raises_value_error(self):
70
75
  """keepalive_time_ms below the 60s minimum must raise ValueError."""
@@ -83,5 +88,54 @@ class TestKeepaliveChannelOptions(unittest.TestCase):
83
88
  self.assertIn(('grpc.keepalive_time_ms', 60000), options)
84
89
 
85
90
 
91
+ class TestClientIdleTimeout(unittest.TestCase):
92
+ """Regression tests for the grpc.client_idle_timeout_ms option — the
93
+ client-side idle-close equivalent of the Go SDK's grpcIdleConnTimeout /
94
+ Node SDK's idleConnectionTimeoutMs, which this SDK previously omitted."""
95
+
96
+ # The backend's own grpc.max_connection_idle enforcement (scalekit's
97
+ # cmd/grpc.go, grpcKeepaliveMaxConnectionIdle) — kept here as a literal,
98
+ # not imported, so this test independently pins the actual production
99
+ # value rather than trusting whatever CLIENT_IDLE_TIMEOUT_CEILING_MS
100
+ # happens to be set to.
101
+ _BACKEND_MAX_CONNECTION_IDLE_MS = 5 * 60 * 1000
102
+
103
+ def test_ceiling_is_strictly_below_backend_max_connection_idle(self):
104
+ """Landing exactly on (or above) the backend's own bound is a race —
105
+ whichever side's timer fires first wins, and the loser is a request
106
+ written into a socket the other side just closed."""
107
+ self.assertLess(CLIENT_IDLE_TIMEOUT_CEILING_MS, self._BACKEND_MAX_CONNECTION_IDLE_MS)
108
+
109
+ def test_derived_value_scales_with_keepalive_time_when_below_ceiling(self):
110
+ small = 1000 # hypothetically below the real MIN_KEEPALIVE_TIME_MS floor, to exercise scaling
111
+ self.assertEqual(
112
+ _client_idle_timeout_ms_for(small),
113
+ small * CLIENT_IDLE_TIMEOUT_PING_CYCLES,
114
+ )
115
+
116
+ def test_derived_value_clamps_to_ceiling_at_default_keepalive(self):
117
+ self.assertEqual(
118
+ _client_idle_timeout_ms_for(DEFAULT_KEEPALIVE_TIME_MS),
119
+ CLIENT_IDLE_TIMEOUT_CEILING_MS,
120
+ )
121
+
122
+ def test_disabled_keepalive_derives_to_zero(self):
123
+ self.assertEqual(_client_idle_timeout_ms_for(0), 0)
124
+
125
+ def test_disabling_keepalive_omits_idle_timeout_option_too(self):
126
+ """keepalive_time_ms=0 must disable BOTH the ping-based and the
127
+ idle-close detection — a partial disable would be a surprising,
128
+ undocumented middle state."""
129
+ _, mock_secure_channel = _build_client(keepalive_time_ms=0)
130
+ mock_secure_channel.assert_called_once()
131
+ _, kwargs = mock_secure_channel.call_args
132
+ options = kwargs["options"]
133
+ self.assertEqual(options, [])
134
+ self.assertNotIn(
135
+ "grpc.client_idle_timeout_ms",
136
+ [name for name, _ in options],
137
+ )
138
+
139
+
86
140
  if __name__ == "__main__":
87
141
  unittest.main()
@@ -0,0 +1,81 @@
1
+ from basetest import BaseTest
2
+
3
+ # A real MCP server resource in the test environment. These tests assert the
4
+ # call shape and the pagination envelope, never the consent contents, so they
5
+ # hold whether or not the resource currently has consents.
6
+ TEST_RESOURCE_ID = "res_90805895235109156"
7
+
8
+
9
+ class TestResourceClient(BaseTest):
10
+ """ Class definition for TestResourceClient Class """
11
+
12
+ def test_list_user_consents(self):
13
+ """ Method to test list user consents for a resource """
14
+ response = self.scalekit_client.resources.list_user_consents(
15
+ resource_id=TEST_RESOURCE_ID
16
+ )
17
+
18
+ self.assertEqual(response[1].code().name, "OK")
19
+ self.assertIsNotNone(response[0].consents)
20
+ self.assertIsInstance(response[0].total_size, int)
21
+
22
+ def test_list_user_consents_with_page_size(self):
23
+ """ Method to test list user consents with a page size """
24
+ response = self.scalekit_client.resources.list_user_consents(
25
+ resource_id=TEST_RESOURCE_ID, page_size=10
26
+ )
27
+
28
+ self.assertEqual(response[1].code().name, "OK")
29
+ self.assertTrue(len(response[0].consents) <= 10)
30
+
31
+ def test_list_user_consents_with_search(self):
32
+ """ Method to test list user consents with a search term """
33
+ response = self.scalekit_client.resources.list_user_consents(
34
+ resource_id=TEST_RESOURCE_ID, search="usr_"
35
+ )
36
+
37
+ self.assertEqual(response[1].code().name, "OK")
38
+ self.assertIsNotNone(response[0].consents)
39
+
40
+ def test_list_user_consents_with_user_ids(self):
41
+ """ Method to test list user consents with an exact user_ids filter """
42
+ response = self.scalekit_client.resources.list_user_consents(
43
+ resource_id=TEST_RESOURCE_ID, user_ids=["usr_does_not_exist"]
44
+ )
45
+
46
+ self.assertEqual(response[1].code().name, "OK")
47
+ self.assertEqual(len(response[0].consents), 0)
48
+
49
+ def test_list_user_consents_user_ids_takes_precedence_over_search(self):
50
+ """ Method to test that user_ids is honoured alongside search """
51
+ response = self.scalekit_client.resources.list_user_consents(
52
+ resource_id=TEST_RESOURCE_ID, user_ids=["usr_does_not_exist"], search="usr_"
53
+ )
54
+
55
+ self.assertEqual(response[1].code().name, "OK")
56
+ self.assertEqual(len(response[0].consents), 0)
57
+
58
+ def test_list_user_consents_without_resource_id(self):
59
+ """ Method to test list user consents without a resource id """
60
+ with self.assertRaises(ValueError) as context:
61
+ self.scalekit_client.resources.list_user_consents(resource_id="")
62
+
63
+ self.assertEqual(str(context.exception), "resource_id is required")
64
+
65
+ def test_revoke_user_consent_without_client_id(self):
66
+ """ Method to test revoke user consent without a client id """
67
+ with self.assertRaises(ValueError) as context:
68
+ self.scalekit_client.resources.revoke_user_consent(
69
+ client_id="", consent_id="usrcnst_1234567890"
70
+ )
71
+
72
+ self.assertEqual(str(context.exception), "client_id is required")
73
+
74
+ def test_revoke_user_consent_without_consent_id(self):
75
+ """ Method to test revoke user consent without a consent id """
76
+ with self.assertRaises(ValueError) as context:
77
+ self.scalekit_client.resources.revoke_user_consent(
78
+ client_id="m2m_1234567890", consent_id=""
79
+ )
80
+
81
+ self.assertEqual(str(context.exception), "consent_id is required")