pipedream 2.1.20__tar.gz → 2.2.0__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.
- {pipedream-2.1.20 → pipedream-2.2.0}/PKG-INFO +4 -1
- {pipedream-2.1.20 → pipedream-2.2.0}/pyproject.toml +4 -1
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/core/client_wrapper.py +2 -2
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/oauth_tokens/client.py +38 -8
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/oauth_tokens/raw_client.py +30 -4
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/pipedream.py +103 -0
- pipedream-2.2.0/src/pipedream/private_key_jwt.py +204 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/LICENSE +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/README.md +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/__init__.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/_default_clients.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/accounts/__init__.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/accounts/client.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/accounts/raw_client.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/actions/__init__.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/actions/client.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/actions/raw_client.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/actions/types/__init__.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/actions/types/actions_list_request_registry.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/app_categories/__init__.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/app_categories/client.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/app_categories/raw_client.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/app_overrides/__init__.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/app_overrides/client.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/app_overrides/raw_client.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/apps/__init__.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/apps/client.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/apps/raw_client.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/apps/types/__init__.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/apps/types/apps_list_request_sort_direction.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/apps/types/apps_list_request_sort_key.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/client.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/components/__init__.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/components/client.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/components/raw_client.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/components/types/__init__.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/components/types/components_list_request_registry.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/core/__init__.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/core/api_error.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/core/datetime_utils.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/core/file.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/core/force_multipart.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/core/http_client.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/core/http_response.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/core/http_sse/__init__.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/core/http_sse/_api.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/core/http_sse/_decoders.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/core/http_sse/_exceptions.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/core/http_sse/_models.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/core/jsonable_encoder.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/core/logging.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/core/oauth_token_provider.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/core/pagination.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/core/parse_error.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/core/pydantic_utilities.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/core/query_encoder.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/core/remove_none_from_dict.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/core/request_options.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/core/serialization.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/deployed_triggers/__init__.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/deployed_triggers/client.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/deployed_triggers/raw_client.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/environment.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/errors/__init__.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/errors/bad_request_error.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/errors/not_found_error.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/errors/too_many_requests_error.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/file_stash/__init__.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/file_stash/client.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/file_stash/raw_client.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/oauth_apps/__init__.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/oauth_apps/client.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/oauth_apps/raw_client.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/oauth_tokens/__init__.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/project_environment/__init__.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/project_environment/client.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/project_environment/raw_client.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/projects/__init__.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/projects/client.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/projects/raw_client.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/proxy/__init__.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/proxy/client.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/proxy/raw_client.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/py.typed +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/tokens/__init__.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/tokens/client.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/tokens/raw_client.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/triggers/__init__.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/triggers/client.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/triggers/raw_client.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/triggers/types/__init__.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/triggers/types/triggers_list_request_registry.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/types/__init__.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/types/account.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/types/account_credentials.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/types/account_id.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/types/app.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/types/app_auth_type.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/types/app_category.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/types/app_override.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/types/app_scope_profiles_item.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/types/app_scope_profiles_item_name.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/types/backend_client_opts.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/types/client_opts.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/types/component.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/types/component_stash.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/types/component_type.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/types/configurable_prop.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/types/configurable_prop_airtable_base_id.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/types/configurable_prop_airtable_field_id.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/types/configurable_prop_airtable_table_id.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/types/configurable_prop_airtable_view_id.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/types/configurable_prop_alert.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/types/configurable_prop_alert_type.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/types/configurable_prop_any.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/types/configurable_prop_any_options_item.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/types/configurable_prop_app.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/types/configurable_prop_apphook.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/types/configurable_prop_base.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/types/configurable_prop_base_type.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/types/configurable_prop_boolean.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/types/configurable_prop_boolean_options_item.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/types/configurable_prop_data_store.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/types/configurable_prop_db.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/types/configurable_prop_dir.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/types/configurable_prop_dir_access_mode.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/types/configurable_prop_discord_channel.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/types/configurable_prop_discord_channel_array.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/types/configurable_prop_http.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/types/configurable_prop_http_request.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/types/configurable_prop_integer.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/types/configurable_prop_integer_array.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/types/configurable_prop_integer_array_options_item.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/types/configurable_prop_integer_options_item.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/types/configurable_prop_object.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/types/configurable_prop_object_options_item.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/types/configurable_prop_sql.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/types/configurable_prop_sql_auth.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/types/configurable_prop_sql_options_item.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/types/configurable_prop_string.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/types/configurable_prop_string_array.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/types/configurable_prop_string_array_options_item.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/types/configurable_prop_string_format.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/types/configurable_prop_string_options_item.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/types/configurable_prop_timer.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/types/configurable_prop_timer_default.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/types/configurable_prop_timer_option.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/types/configurable_prop_timer_static.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/types/configure_prop_options.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/types/configure_prop_options_item.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/types/configure_prop_opts.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/types/configure_prop_response.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/types/configured_prop_value.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/types/configured_prop_value_any.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/types/configured_prop_value_app.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/types/configured_prop_value_boolean.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/types/configured_prop_value_integer.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/types/configured_prop_value_object.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/types/configured_prop_value_sql.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/types/configured_prop_value_string.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/types/configured_prop_value_string_array.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/types/configured_props.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/types/connect_token.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/types/connect_usage.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/types/connect_usage_response.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/types/create_o_auth_token_response.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/types/create_token_response.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/types/delete_trigger_opts.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/types/deploy_trigger_response.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/types/deployed_component.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/types/dynamic_props.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/types/emitted_event.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/types/emitter.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/types/emitter_type.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/types/error_response.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/types/external_user.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/types/get_accounts_response.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/types/get_app_category_response.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/types/get_app_response.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/types/get_apps_response.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/types/get_component_response.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/types/get_components_response.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/types/get_trigger_events_response.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/types/get_trigger_response.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/types/get_trigger_webhooks_response.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/types/get_trigger_workflows_response.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/types/get_triggers_response.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/types/get_users_response.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/types/get_webhook_response.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/types/get_webhook_with_signing_key_response.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/types/http_interface.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/types/http_request_auth.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/types/http_request_auth_type.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/types/http_request_body.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/types/http_request_body_mode.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/types/http_request_body_type.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/types/http_request_config.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/types/http_request_field.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/types/list_accounts_response.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/types/list_app_categories_response.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/types/list_app_overrides_response.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/types/list_apps_response.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/types/list_oauth_apps_response.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/types/list_projects_response.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/types/oauth_app.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/types/observation.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/types/observation_error.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/types/page_info.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/types/project.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/types/project_environment.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/types/project_info_response.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/types/project_info_response_app.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/types/prop_option.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/types/prop_option_nested.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/types/prop_option_value.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/types/proxy_response.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/types/proxy_response_binary.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/types/reload_props_opts.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/types/reload_props_response.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/types/run_action_opts_stash_id.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/types/run_action_response.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/types/set_webhook_response.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/types/start_connect_opts.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/types/stash_id.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/types/timer_cron.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/types/timer_interface.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/types/timer_interval.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/types/too_many_requests_error_body.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/types/tool_annotations.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/types/trigger_webhook.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/types/validate_token_response.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/types/webhook.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/types/webhook_with_optional_signing_key.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/types/webhook_with_signing_key.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/usage/__init__.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/usage/client.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/usage/raw_client.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/users/__init__.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/users/client.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/users/raw_client.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/version.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/workflows/__init__.py +0 -0
- {pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/workflows/client.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: pipedream
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.2.0
|
|
4
4
|
Summary:
|
|
5
5
|
Requires-Python: >=3.10,<4.0
|
|
6
6
|
Classifier: Intended Audience :: Developers
|
|
@@ -20,11 +20,14 @@ Classifier: Programming Language :: Python :: 3.15
|
|
|
20
20
|
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
21
21
|
Classifier: Typing :: Typed
|
|
22
22
|
Provides-Extra: aiohttp
|
|
23
|
+
Provides-Extra: private-key
|
|
23
24
|
Requires-Dist: aiohttp (>=3.13.4,<4) ; (python_version >= "3.9") and (extra == "aiohttp")
|
|
25
|
+
Requires-Dist: cryptography (>=3.4.0) ; extra == "private-key"
|
|
24
26
|
Requires-Dist: httpx (>=0.21.2)
|
|
25
27
|
Requires-Dist: httpx-aiohttp (==0.1.8) ; (python_version >= "3.9") and (extra == "aiohttp")
|
|
26
28
|
Requires-Dist: pydantic (>=1.9.2)
|
|
27
29
|
Requires-Dist: pydantic-core (>=2.18.2,<3.0.0)
|
|
30
|
+
Requires-Dist: pyjwt (>=2.8.0,<3) ; extra == "private-key"
|
|
28
31
|
Requires-Dist: typing_extensions (>=4.0.0)
|
|
29
32
|
Project-URL: Repository, https://github.com/PipedreamHQ/pipedream-sdk-python
|
|
30
33
|
Description-Content-Type: text/markdown
|
|
@@ -4,7 +4,7 @@ dynamic = ["version"]
|
|
|
4
4
|
|
|
5
5
|
[tool.poetry]
|
|
6
6
|
name = "pipedream"
|
|
7
|
-
version = "2.
|
|
7
|
+
version = "2.2.0"
|
|
8
8
|
description = ""
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
authors = []
|
|
@@ -38,10 +38,12 @@ Repository = 'https://github.com/PipedreamHQ/pipedream-sdk-python'
|
|
|
38
38
|
[tool.poetry.dependencies]
|
|
39
39
|
python = "^3.10"
|
|
40
40
|
aiohttp = { version = ">=3.13.4,<4", optional = true, python = ">=3.9"}
|
|
41
|
+
cryptography = { version = ">=3.4.0", optional = true}
|
|
41
42
|
httpx = ">=0.21.2"
|
|
42
43
|
httpx-aiohttp = { version = "0.1.8", optional = true, python = ">=3.9"}
|
|
43
44
|
pydantic = ">= 1.9.2"
|
|
44
45
|
pydantic-core = ">=2.18.2,<3.0.0"
|
|
46
|
+
pyjwt = { version = ">=2.8.0,<3", optional = true}
|
|
45
47
|
typing_extensions = ">= 4.0.0"
|
|
46
48
|
|
|
47
49
|
[tool.poetry.group.dev.dependencies]
|
|
@@ -93,4 +95,5 @@ requires = ["poetry-core"]
|
|
|
93
95
|
build-backend = "poetry.core.masonry.api"
|
|
94
96
|
|
|
95
97
|
[tool.poetry.extras]
|
|
98
|
+
private-key=["pyjwt", "cryptography"]
|
|
96
99
|
aiohttp=["aiohttp", "httpx-aiohttp"]
|
|
@@ -34,12 +34,12 @@ class BaseClientWrapper:
|
|
|
34
34
|
import platform
|
|
35
35
|
|
|
36
36
|
headers: typing.Dict[str, str] = {
|
|
37
|
-
"User-Agent": "pipedream/2.
|
|
37
|
+
"User-Agent": "pipedream/2.2.0",
|
|
38
38
|
"X-Fern-Language": "Python",
|
|
39
39
|
"X-Fern-Runtime": f"python/{platform.python_version()}",
|
|
40
40
|
"X-Fern-Platform": f"{platform.system().lower()}/{platform.release()}",
|
|
41
41
|
"X-Fern-SDK-Name": "pipedream",
|
|
42
|
-
"X-Fern-SDK-Version": "2.
|
|
42
|
+
"X-Fern-SDK-Version": "2.2.0",
|
|
43
43
|
**(self.get_custom_headers() or {}),
|
|
44
44
|
}
|
|
45
45
|
if self._project_environment is not None:
|
|
@@ -30,7 +30,11 @@ class OauthTokensClient:
|
|
|
30
30
|
self,
|
|
31
31
|
*,
|
|
32
32
|
client_id: str,
|
|
33
|
-
client_secret: str,
|
|
33
|
+
client_secret: typing.Optional[str] = OMIT,
|
|
34
|
+
client_assertion_type: typing.Optional[
|
|
35
|
+
typing.Literal["urn:ietf:params:oauth:client-assertion-type:jwt-bearer"]
|
|
36
|
+
] = OMIT,
|
|
37
|
+
client_assertion: typing.Optional[str] = OMIT,
|
|
34
38
|
scope: typing.Optional[str] = OMIT,
|
|
35
39
|
request_options: typing.Optional[RequestOptions] = None,
|
|
36
40
|
) -> CreateOAuthTokenResponse:
|
|
@@ -41,7 +45,14 @@ class OauthTokensClient:
|
|
|
41
45
|
----------
|
|
42
46
|
client_id : str
|
|
43
47
|
|
|
44
|
-
client_secret : str
|
|
48
|
+
client_secret : typing.Optional[str]
|
|
49
|
+
The client secret, for clients that authenticate with a client secret.
|
|
50
|
+
|
|
51
|
+
client_assertion_type : typing.Optional[typing.Literal["urn:ietf:params:oauth:client-assertion-type:jwt-bearer"]]
|
|
52
|
+
Required with `client_assertion`.
|
|
53
|
+
|
|
54
|
+
client_assertion : typing.Optional[str]
|
|
55
|
+
For clients that authenticate with a public key: a JWT signed with the client's private key (ES256 or RS256). Claims: `iss` and `sub` set to the client ID, `aud` set to `https://api.pipedream.com`, `exp` at most 1 hour ahead, and a unique `jti`. Sign a new assertion for every request, including retries.
|
|
45
56
|
|
|
46
57
|
scope : typing.Optional[str]
|
|
47
58
|
Optional space-separated scopes for the access token. Defaults to `*`.
|
|
@@ -65,11 +76,15 @@ class OauthTokensClient:
|
|
|
65
76
|
)
|
|
66
77
|
client.oauth_tokens.create(
|
|
67
78
|
client_id="client_id",
|
|
68
|
-
client_secret="client_secret",
|
|
69
79
|
)
|
|
70
80
|
"""
|
|
71
81
|
_response = self._raw_client.create(
|
|
72
|
-
client_id=client_id,
|
|
82
|
+
client_id=client_id,
|
|
83
|
+
client_secret=client_secret,
|
|
84
|
+
client_assertion_type=client_assertion_type,
|
|
85
|
+
client_assertion=client_assertion,
|
|
86
|
+
scope=scope,
|
|
87
|
+
request_options=request_options,
|
|
73
88
|
)
|
|
74
89
|
return _response.data
|
|
75
90
|
|
|
@@ -93,7 +108,11 @@ class AsyncOauthTokensClient:
|
|
|
93
108
|
self,
|
|
94
109
|
*,
|
|
95
110
|
client_id: str,
|
|
96
|
-
client_secret: str,
|
|
111
|
+
client_secret: typing.Optional[str] = OMIT,
|
|
112
|
+
client_assertion_type: typing.Optional[
|
|
113
|
+
typing.Literal["urn:ietf:params:oauth:client-assertion-type:jwt-bearer"]
|
|
114
|
+
] = OMIT,
|
|
115
|
+
client_assertion: typing.Optional[str] = OMIT,
|
|
97
116
|
scope: typing.Optional[str] = OMIT,
|
|
98
117
|
request_options: typing.Optional[RequestOptions] = None,
|
|
99
118
|
) -> CreateOAuthTokenResponse:
|
|
@@ -104,7 +123,14 @@ class AsyncOauthTokensClient:
|
|
|
104
123
|
----------
|
|
105
124
|
client_id : str
|
|
106
125
|
|
|
107
|
-
client_secret : str
|
|
126
|
+
client_secret : typing.Optional[str]
|
|
127
|
+
The client secret, for clients that authenticate with a client secret.
|
|
128
|
+
|
|
129
|
+
client_assertion_type : typing.Optional[typing.Literal["urn:ietf:params:oauth:client-assertion-type:jwt-bearer"]]
|
|
130
|
+
Required with `client_assertion`.
|
|
131
|
+
|
|
132
|
+
client_assertion : typing.Optional[str]
|
|
133
|
+
For clients that authenticate with a public key: a JWT signed with the client's private key (ES256 or RS256). Claims: `iss` and `sub` set to the client ID, `aud` set to `https://api.pipedream.com`, `exp` at most 1 hour ahead, and a unique `jti`. Sign a new assertion for every request, including retries.
|
|
108
134
|
|
|
109
135
|
scope : typing.Optional[str]
|
|
110
136
|
Optional space-separated scopes for the access token. Defaults to `*`.
|
|
@@ -133,13 +159,17 @@ class AsyncOauthTokensClient:
|
|
|
133
159
|
async def main() -> None:
|
|
134
160
|
await client.oauth_tokens.create(
|
|
135
161
|
client_id="client_id",
|
|
136
|
-
client_secret="client_secret",
|
|
137
162
|
)
|
|
138
163
|
|
|
139
164
|
|
|
140
165
|
asyncio.run(main())
|
|
141
166
|
"""
|
|
142
167
|
_response = await self._raw_client.create(
|
|
143
|
-
client_id=client_id,
|
|
168
|
+
client_id=client_id,
|
|
169
|
+
client_secret=client_secret,
|
|
170
|
+
client_assertion_type=client_assertion_type,
|
|
171
|
+
client_assertion=client_assertion,
|
|
172
|
+
scope=scope,
|
|
173
|
+
request_options=request_options,
|
|
144
174
|
)
|
|
145
175
|
return _response.data
|
|
@@ -25,7 +25,11 @@ class RawOauthTokensClient:
|
|
|
25
25
|
self,
|
|
26
26
|
*,
|
|
27
27
|
client_id: str,
|
|
28
|
-
client_secret: str,
|
|
28
|
+
client_secret: typing.Optional[str] = OMIT,
|
|
29
|
+
client_assertion_type: typing.Optional[
|
|
30
|
+
typing.Literal["urn:ietf:params:oauth:client-assertion-type:jwt-bearer"]
|
|
31
|
+
] = OMIT,
|
|
32
|
+
client_assertion: typing.Optional[str] = OMIT,
|
|
29
33
|
scope: typing.Optional[str] = OMIT,
|
|
30
34
|
request_options: typing.Optional[RequestOptions] = None,
|
|
31
35
|
) -> HttpResponse[CreateOAuthTokenResponse]:
|
|
@@ -36,7 +40,14 @@ class RawOauthTokensClient:
|
|
|
36
40
|
----------
|
|
37
41
|
client_id : str
|
|
38
42
|
|
|
39
|
-
client_secret : str
|
|
43
|
+
client_secret : typing.Optional[str]
|
|
44
|
+
The client secret, for clients that authenticate with a client secret.
|
|
45
|
+
|
|
46
|
+
client_assertion_type : typing.Optional[typing.Literal["urn:ietf:params:oauth:client-assertion-type:jwt-bearer"]]
|
|
47
|
+
Required with `client_assertion`.
|
|
48
|
+
|
|
49
|
+
client_assertion : typing.Optional[str]
|
|
50
|
+
For clients that authenticate with a public key: a JWT signed with the client's private key (ES256 or RS256). Claims: `iss` and `sub` set to the client ID, `aud` set to `https://api.pipedream.com`, `exp` at most 1 hour ahead, and a unique `jti`. Sign a new assertion for every request, including retries.
|
|
40
51
|
|
|
41
52
|
scope : typing.Optional[str]
|
|
42
53
|
Optional space-separated scopes for the access token. Defaults to `*`.
|
|
@@ -55,6 +66,8 @@ class RawOauthTokensClient:
|
|
|
55
66
|
json={
|
|
56
67
|
"client_id": client_id,
|
|
57
68
|
"client_secret": client_secret,
|
|
69
|
+
"client_assertion_type": client_assertion_type,
|
|
70
|
+
"client_assertion": client_assertion,
|
|
58
71
|
"scope": scope,
|
|
59
72
|
"grant_type": "client_credentials",
|
|
60
73
|
},
|
|
@@ -103,7 +116,11 @@ class AsyncRawOauthTokensClient:
|
|
|
103
116
|
self,
|
|
104
117
|
*,
|
|
105
118
|
client_id: str,
|
|
106
|
-
client_secret: str,
|
|
119
|
+
client_secret: typing.Optional[str] = OMIT,
|
|
120
|
+
client_assertion_type: typing.Optional[
|
|
121
|
+
typing.Literal["urn:ietf:params:oauth:client-assertion-type:jwt-bearer"]
|
|
122
|
+
] = OMIT,
|
|
123
|
+
client_assertion: typing.Optional[str] = OMIT,
|
|
107
124
|
scope: typing.Optional[str] = OMIT,
|
|
108
125
|
request_options: typing.Optional[RequestOptions] = None,
|
|
109
126
|
) -> AsyncHttpResponse[CreateOAuthTokenResponse]:
|
|
@@ -114,7 +131,14 @@ class AsyncRawOauthTokensClient:
|
|
|
114
131
|
----------
|
|
115
132
|
client_id : str
|
|
116
133
|
|
|
117
|
-
client_secret : str
|
|
134
|
+
client_secret : typing.Optional[str]
|
|
135
|
+
The client secret, for clients that authenticate with a client secret.
|
|
136
|
+
|
|
137
|
+
client_assertion_type : typing.Optional[typing.Literal["urn:ietf:params:oauth:client-assertion-type:jwt-bearer"]]
|
|
138
|
+
Required with `client_assertion`.
|
|
139
|
+
|
|
140
|
+
client_assertion : typing.Optional[str]
|
|
141
|
+
For clients that authenticate with a public key: a JWT signed with the client's private key (ES256 or RS256). Claims: `iss` and `sub` set to the client ID, `aud` set to `https://api.pipedream.com`, `exp` at most 1 hour ahead, and a unique `jti`. Sign a new assertion for every request, including retries.
|
|
118
142
|
|
|
119
143
|
scope : typing.Optional[str]
|
|
120
144
|
Optional space-separated scopes for the access token. Defaults to `*`.
|
|
@@ -133,6 +157,8 @@ class AsyncRawOauthTokensClient:
|
|
|
133
157
|
json={
|
|
134
158
|
"client_id": client_id,
|
|
135
159
|
"client_secret": client_secret,
|
|
160
|
+
"client_assertion_type": client_assertion_type,
|
|
161
|
+
"client_assertion": client_assertion,
|
|
136
162
|
"scope": scope,
|
|
137
163
|
"grant_type": "client_credentials",
|
|
138
164
|
},
|
|
@@ -5,6 +5,12 @@ import httpx
|
|
|
5
5
|
from .client import AsyncClient, Client
|
|
6
6
|
from .core.client_wrapper import AsyncClientWrapper, SyncClientWrapper
|
|
7
7
|
from .core.logging import LogConfig, Logger
|
|
8
|
+
from .private_key_jwt import (
|
|
9
|
+
AsyncPrivateKeyJwtTokenProvider,
|
|
10
|
+
ClientAssertionSigner,
|
|
11
|
+
PrivateKeyJwtTokenProvider,
|
|
12
|
+
issuer_from_base_url,
|
|
13
|
+
)
|
|
8
14
|
from .types.project_environment import ProjectEnvironment
|
|
9
15
|
from .workflows.client import AsyncWorkflowsClient, WorkflowsClient
|
|
10
16
|
|
|
@@ -31,6 +37,52 @@ def install_request_hook(
|
|
|
31
37
|
).append(hook)
|
|
32
38
|
|
|
33
39
|
|
|
40
|
+
def _resolve_credentials(
|
|
41
|
+
client_secret: typing.Optional[str],
|
|
42
|
+
private_key: typing.Optional[str],
|
|
43
|
+
) -> typing.Tuple[typing.Optional[str], typing.Optional[str]]:
|
|
44
|
+
"""Returns (client_secret, private_key) with at most one of them set.
|
|
45
|
+
|
|
46
|
+
An explicitly passed credential wins over the other one in the environment.
|
|
47
|
+
Passing both, or setting both PIPEDREAM_CLIENT_SECRET and
|
|
48
|
+
PIPEDREAM_PRIVATE_KEY with neither passed, raises ValueError.
|
|
49
|
+
"""
|
|
50
|
+
env_secret = os.getenv("PIPEDREAM_CLIENT_SECRET")
|
|
51
|
+
# client_secret defaults to the environment variable, so a value equal to
|
|
52
|
+
# it is treated as coming from the environment.
|
|
53
|
+
secret_passed = bool(client_secret) and client_secret != env_secret
|
|
54
|
+
if private_key and secret_passed:
|
|
55
|
+
raise ValueError("Pass either client_secret or private_key, not both")
|
|
56
|
+
if private_key:
|
|
57
|
+
return None, private_key
|
|
58
|
+
if secret_passed:
|
|
59
|
+
return client_secret, None
|
|
60
|
+
env_key = os.getenv("PIPEDREAM_PRIVATE_KEY")
|
|
61
|
+
if client_secret and env_key:
|
|
62
|
+
raise ValueError(
|
|
63
|
+
"Both PIPEDREAM_CLIENT_SECRET and PIPEDREAM_PRIVATE_KEY are set; set only the one your client uses"
|
|
64
|
+
)
|
|
65
|
+
return client_secret, env_key
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def _assertion_signer(
|
|
69
|
+
client_id: typing.Optional[str],
|
|
70
|
+
private_key: str,
|
|
71
|
+
key_id: typing.Optional[str],
|
|
72
|
+
base_url: str,
|
|
73
|
+
) -> ClientAssertionSigner:
|
|
74
|
+
if not client_id:
|
|
75
|
+
raise ValueError("client_id is required when authenticating with private_key")
|
|
76
|
+
return ClientAssertionSigner(
|
|
77
|
+
client_id=client_id,
|
|
78
|
+
private_key=private_key,
|
|
79
|
+
key_id=key_id or os.getenv("PIPEDREAM_KEY_ID"),
|
|
80
|
+
# The assertion audience is the API's issuer identifier: the base URL's
|
|
81
|
+
# origin (https://api.pipedream.com by default).
|
|
82
|
+
audience=issuer_from_base_url(base_url),
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
|
|
34
86
|
class Pipedream(Client):
|
|
35
87
|
|
|
36
88
|
def __init__(
|
|
@@ -39,6 +91,8 @@ class Pipedream(Client):
|
|
|
39
91
|
access_token: typing.Optional[str] = os.getenv("PIPEDREAM_ACCESS_TOKEN"),
|
|
40
92
|
client_id: typing.Optional[str] = os.getenv("PIPEDREAM_CLIENT_ID"),
|
|
41
93
|
client_secret: typing.Optional[str] = os.getenv("PIPEDREAM_CLIENT_SECRET"),
|
|
94
|
+
private_key: typing.Optional[str] = None,
|
|
95
|
+
key_id: typing.Optional[str] = None,
|
|
42
96
|
project_id: typing.Optional[str] = os.getenv("PIPEDREAM_PROJECT_ID"),
|
|
43
97
|
project_environment: typing.Optional[ProjectEnvironment] = os.getenv(
|
|
44
98
|
"PIPEDREAM_PROJECT_ENVIRONMENT",
|
|
@@ -73,8 +127,30 @@ class Pipedream(Client):
|
|
|
73
127
|
logging=logging,
|
|
74
128
|
)
|
|
75
129
|
|
|
130
|
+
client_secret, private_key = _resolve_credentials(client_secret, private_key)
|
|
131
|
+
|
|
76
132
|
if access_token:
|
|
77
133
|
super().__init__(token=(lambda: access_token), **common_kwargs)
|
|
134
|
+
elif private_key:
|
|
135
|
+
signer = _assertion_signer(client_id, private_key, key_id, resolved_base_url)
|
|
136
|
+
super().__init__(token=lambda: self._token_provider.get_token(), **common_kwargs)
|
|
137
|
+
# Token requests use their own unauthenticated wrapper over the same
|
|
138
|
+
# HTTP client, like the generated client-secret flow.
|
|
139
|
+
wrapper = self._client_wrapper
|
|
140
|
+
self._token_provider = PrivateKeyJwtTokenProvider(
|
|
141
|
+
client_id=typing.cast(str, client_id),
|
|
142
|
+
signer=signer,
|
|
143
|
+
client_wrapper=SyncClientWrapper(
|
|
144
|
+
project_id=project_id,
|
|
145
|
+
project_environment=project_environment,
|
|
146
|
+
headers=headers,
|
|
147
|
+
base_url=wrapper.get_base_url(),
|
|
148
|
+
timeout=wrapper.get_timeout(),
|
|
149
|
+
max_retries=wrapper.get_max_retries(),
|
|
150
|
+
logging=logging,
|
|
151
|
+
httpx_client=wrapper.httpx_client.httpx_client,
|
|
152
|
+
),
|
|
153
|
+
)
|
|
78
154
|
else:
|
|
79
155
|
super().__init__(client_id=client_id, client_secret=client_secret, **common_kwargs)
|
|
80
156
|
|
|
@@ -101,6 +177,8 @@ class AsyncPipedream(AsyncClient):
|
|
|
101
177
|
access_token: typing.Optional[str] = os.getenv("PIPEDREAM_ACCESS_TOKEN"),
|
|
102
178
|
client_id: typing.Optional[str] = os.getenv("PIPEDREAM_CLIENT_ID"),
|
|
103
179
|
client_secret: typing.Optional[str] = os.getenv("PIPEDREAM_CLIENT_SECRET"),
|
|
180
|
+
private_key: typing.Optional[str] = None,
|
|
181
|
+
key_id: typing.Optional[str] = None,
|
|
104
182
|
project_id: typing.Optional[str] = os.getenv("PIPEDREAM_PROJECT_ID"),
|
|
105
183
|
project_environment: typing.Optional[ProjectEnvironment] = os.getenv(
|
|
106
184
|
"PIPEDREAM_PROJECT_ENVIRONMENT",
|
|
@@ -135,8 +213,33 @@ class AsyncPipedream(AsyncClient):
|
|
|
135
213
|
logging=logging,
|
|
136
214
|
)
|
|
137
215
|
|
|
216
|
+
client_secret, private_key = _resolve_credentials(client_secret, private_key)
|
|
217
|
+
|
|
138
218
|
if access_token:
|
|
139
219
|
super().__init__(token=(lambda: access_token), **common_kwargs)
|
|
220
|
+
elif private_key:
|
|
221
|
+
signer = _assertion_signer(client_id, private_key, key_id, resolved_base_url)
|
|
222
|
+
super().__init__(token=(lambda: ""), **common_kwargs)
|
|
223
|
+
# Wire the async token provider the way the generated client-secret
|
|
224
|
+
# flow does: no sync token, an async one, and token requests on
|
|
225
|
+
# their own unauthenticated wrapper over the same HTTP client.
|
|
226
|
+
wrapper = self._client_wrapper
|
|
227
|
+
token_provider = AsyncPrivateKeyJwtTokenProvider(
|
|
228
|
+
client_id=typing.cast(str, client_id),
|
|
229
|
+
signer=signer,
|
|
230
|
+
client_wrapper=AsyncClientWrapper(
|
|
231
|
+
project_id=project_id,
|
|
232
|
+
project_environment=project_environment,
|
|
233
|
+
headers=headers,
|
|
234
|
+
base_url=wrapper.get_base_url(),
|
|
235
|
+
timeout=wrapper.get_timeout(),
|
|
236
|
+
max_retries=wrapper.get_max_retries(),
|
|
237
|
+
logging=logging,
|
|
238
|
+
httpx_client=wrapper.httpx_client.httpx_client,
|
|
239
|
+
),
|
|
240
|
+
)
|
|
241
|
+
wrapper._token = None
|
|
242
|
+
wrapper._async_token = token_provider.get_token
|
|
140
243
|
else:
|
|
141
244
|
super().__init__(client_id=client_id, client_secret=client_secret, **common_kwargs)
|
|
142
245
|
|
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
"""Client assertions for private_key_jwt client authentication (RFC 7523).
|
|
2
|
+
|
|
3
|
+
An OAuth client that registered a public key authenticates at the token
|
|
4
|
+
endpoint with a short-lived JWT signed by the matching private key, instead of
|
|
5
|
+
a client secret. Requires the optional ``private-key`` extra:
|
|
6
|
+
``pip install "pipedream[private-key]"`` (PyJWT with cryptography).
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
import asyncio
|
|
10
|
+
import datetime as dt
|
|
11
|
+
import json
|
|
12
|
+
import threading
|
|
13
|
+
import time
|
|
14
|
+
import typing
|
|
15
|
+
import uuid
|
|
16
|
+
from urllib.parse import urlsplit
|
|
17
|
+
|
|
18
|
+
import httpx
|
|
19
|
+
from .core.api_error import ApiError
|
|
20
|
+
from .core.client_wrapper import AsyncClientWrapper, SyncClientWrapper
|
|
21
|
+
from .oauth_tokens.client import AsyncOauthTokensClient, OauthTokensClient
|
|
22
|
+
from .types.create_o_auth_token_response import CreateOAuthTokenResponse
|
|
23
|
+
|
|
24
|
+
CLIENT_ASSERTION_TYPE: typing.Literal["urn:ietf:params:oauth:client-assertion-type:jwt-bearer"] = (
|
|
25
|
+
"urn:ietf:params:oauth:client-assertion-type:jwt-bearer"
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
# Assertions are single-use and only need to outlive one token request.
|
|
29
|
+
_ASSERTION_LIFETIME_SECONDS = 60
|
|
30
|
+
# Token requests authenticated with an assertion are retried here rather than
|
|
31
|
+
# by the HTTP client, so each attempt carries a newly signed assertion: the
|
|
32
|
+
# server rejects a reused one.
|
|
33
|
+
_MAX_RETRIES = 2
|
|
34
|
+
_TOKEN_BUFFER = dt.timedelta(minutes=2)
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def issuer_from_base_url(base_url: str) -> str:
|
|
38
|
+
"""The API's issuer identifier: the base URL's origin, without a trailing slash."""
|
|
39
|
+
parts = urlsplit(base_url)
|
|
40
|
+
return f"{parts.scheme}://{parts.netloc}"
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
class ClientAssertionSigner:
|
|
44
|
+
"""Signs a new client assertion on every call to :meth:`sign`.
|
|
45
|
+
|
|
46
|
+
The assertion is a JWT with ``iss`` and ``sub`` set to the client ID, the
|
|
47
|
+
given ``aud``, a 60-second lifetime, and a random single-use ``jti``. The
|
|
48
|
+
private key may be a PEM string (PKCS#8, PKCS#1, or SEC1) or a JWK as a JSON
|
|
49
|
+
string; EC P-256 keys sign with ES256 and RSA keys with RS256. ``key_id``
|
|
50
|
+
is sent as the ``kid`` header and defaults to the JWK's ``kid``, if any.
|
|
51
|
+
The key is parsed and validated on construction.
|
|
52
|
+
"""
|
|
53
|
+
|
|
54
|
+
def __init__(self, *, client_id: str, private_key: str, audience: str, key_id: typing.Optional[str] = None):
|
|
55
|
+
try:
|
|
56
|
+
import jwt # noqa: F401 (PyJWT)
|
|
57
|
+
from cryptography.hazmat.primitives.asymmetric import ec, rsa
|
|
58
|
+
except ImportError as e:
|
|
59
|
+
raise ImportError(
|
|
60
|
+
'Authenticating with a private key requires the "private-key" extra: '
|
|
61
|
+
'pip install "pipedream[private-key]"'
|
|
62
|
+
) from e
|
|
63
|
+
|
|
64
|
+
self._client_id = client_id
|
|
65
|
+
self._audience = audience
|
|
66
|
+
self._key, jwk_kid = _load_private_key(private_key.strip())
|
|
67
|
+
self._key_id = key_id or jwk_kid
|
|
68
|
+
|
|
69
|
+
if isinstance(self._key, ec.EllipticCurvePrivateKey) and isinstance(self._key.curve, ec.SECP256R1):
|
|
70
|
+
self._alg = "ES256"
|
|
71
|
+
elif isinstance(self._key, rsa.RSAPrivateKey):
|
|
72
|
+
self._alg = "RS256"
|
|
73
|
+
else:
|
|
74
|
+
raise ValueError("private_key must be an EC P-256 key (ES256) or an RSA key (RS256)")
|
|
75
|
+
|
|
76
|
+
def sign(self) -> str:
|
|
77
|
+
import jwt
|
|
78
|
+
|
|
79
|
+
now = int(time.time())
|
|
80
|
+
headers: typing.Dict[str, str] = {"typ": "client-authentication+jwt"}
|
|
81
|
+
if self._key_id:
|
|
82
|
+
headers["kid"] = self._key_id
|
|
83
|
+
claims = {
|
|
84
|
+
"iss": self._client_id,
|
|
85
|
+
"sub": self._client_id,
|
|
86
|
+
"aud": self._audience,
|
|
87
|
+
"iat": now,
|
|
88
|
+
"exp": now + _ASSERTION_LIFETIME_SECONDS,
|
|
89
|
+
"jti": str(uuid.uuid4()),
|
|
90
|
+
}
|
|
91
|
+
return jwt.encode(claims, typing.cast(typing.Any, self._key), algorithm=self._alg, headers=headers)
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
def _load_private_key(text: str) -> typing.Tuple[typing.Any, typing.Optional[str]]:
|
|
95
|
+
import jwt
|
|
96
|
+
from cryptography.hazmat.primitives.serialization import load_pem_private_key
|
|
97
|
+
|
|
98
|
+
try:
|
|
99
|
+
if text.startswith("{"):
|
|
100
|
+
jwk = json.loads(text)
|
|
101
|
+
key = jwt.PyJWK(jwk).key
|
|
102
|
+
kid = jwk.get("kid") if isinstance(jwk.get("kid"), str) else None
|
|
103
|
+
if not hasattr(key, "sign"):
|
|
104
|
+
raise ValueError("not a private key")
|
|
105
|
+
return key, kid
|
|
106
|
+
return load_pem_private_key(text.encode(), password=None), None
|
|
107
|
+
except Exception as e:
|
|
108
|
+
raise ValueError(
|
|
109
|
+
"private_key must be a private key in PEM format or a JWK (JSON). "
|
|
110
|
+
"If you passed a public key, pass the private key instead."
|
|
111
|
+
) from e
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
def _is_retryable(error: Exception) -> bool:
|
|
115
|
+
# Rate limits, timeouts, connection failures, and server errors are
|
|
116
|
+
# transient; 4xx errors such as invalid_client are not.
|
|
117
|
+
if isinstance(error, (httpx.TimeoutException, httpx.TransportError)):
|
|
118
|
+
return True
|
|
119
|
+
if isinstance(error, ApiError):
|
|
120
|
+
status = error.status_code
|
|
121
|
+
return status is None or status in (408, 429) or status >= 500
|
|
122
|
+
return False
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
def _expires_at(token: CreateOAuthTokenResponse) -> dt.datetime:
|
|
126
|
+
return dt.datetime.now() + dt.timedelta(seconds=token.expires_in) - _TOKEN_BUFFER
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
class PrivateKeyJwtTokenProvider:
|
|
130
|
+
"""Retrieves and caches an OAuth access token, authenticating with client assertions."""
|
|
131
|
+
|
|
132
|
+
def __init__(self, *, client_id: str, signer: ClientAssertionSigner, client_wrapper: SyncClientWrapper):
|
|
133
|
+
self._client_id = client_id
|
|
134
|
+
self._signer = signer
|
|
135
|
+
self._auth_client = OauthTokensClient(client_wrapper=client_wrapper)
|
|
136
|
+
self._access_token: typing.Optional[str] = None
|
|
137
|
+
self._expires_at = dt.datetime.now()
|
|
138
|
+
self._lock = threading.Lock()
|
|
139
|
+
|
|
140
|
+
def get_token(self) -> str:
|
|
141
|
+
if self._access_token and self._expires_at > dt.datetime.now():
|
|
142
|
+
return self._access_token
|
|
143
|
+
with self._lock:
|
|
144
|
+
if self._access_token and self._expires_at > dt.datetime.now():
|
|
145
|
+
return self._access_token
|
|
146
|
+
token = self._request_token()
|
|
147
|
+
self._access_token = token.access_token
|
|
148
|
+
self._expires_at = _expires_at(token)
|
|
149
|
+
return self._access_token
|
|
150
|
+
|
|
151
|
+
def _request_token(self) -> CreateOAuthTokenResponse:
|
|
152
|
+
attempt = 0
|
|
153
|
+
while True:
|
|
154
|
+
try:
|
|
155
|
+
return self._auth_client.create(
|
|
156
|
+
client_id=self._client_id,
|
|
157
|
+
client_assertion_type=CLIENT_ASSERTION_TYPE,
|
|
158
|
+
client_assertion=self._signer.sign(),
|
|
159
|
+
request_options={"max_retries": 0},
|
|
160
|
+
)
|
|
161
|
+
except Exception as e:
|
|
162
|
+
if attempt >= _MAX_RETRIES or not _is_retryable(e):
|
|
163
|
+
raise
|
|
164
|
+
time.sleep(0.5 * 2**attempt)
|
|
165
|
+
attempt += 1
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
class AsyncPrivateKeyJwtTokenProvider:
|
|
169
|
+
"""Async variant of :class:`PrivateKeyJwtTokenProvider`."""
|
|
170
|
+
|
|
171
|
+
def __init__(self, *, client_id: str, signer: ClientAssertionSigner, client_wrapper: AsyncClientWrapper):
|
|
172
|
+
self._client_id = client_id
|
|
173
|
+
self._signer = signer
|
|
174
|
+
self._auth_client = AsyncOauthTokensClient(client_wrapper=client_wrapper)
|
|
175
|
+
self._access_token: typing.Optional[str] = None
|
|
176
|
+
self._expires_at = dt.datetime.now()
|
|
177
|
+
self._lock = asyncio.Lock()
|
|
178
|
+
|
|
179
|
+
async def get_token(self) -> str:
|
|
180
|
+
if self._access_token and self._expires_at > dt.datetime.now():
|
|
181
|
+
return self._access_token
|
|
182
|
+
async with self._lock:
|
|
183
|
+
if self._access_token and self._expires_at > dt.datetime.now():
|
|
184
|
+
return self._access_token
|
|
185
|
+
token = await self._request_token()
|
|
186
|
+
self._access_token = token.access_token
|
|
187
|
+
self._expires_at = _expires_at(token)
|
|
188
|
+
return self._access_token
|
|
189
|
+
|
|
190
|
+
async def _request_token(self) -> CreateOAuthTokenResponse:
|
|
191
|
+
attempt = 0
|
|
192
|
+
while True:
|
|
193
|
+
try:
|
|
194
|
+
return await self._auth_client.create(
|
|
195
|
+
client_id=self._client_id,
|
|
196
|
+
client_assertion_type=CLIENT_ASSERTION_TYPE,
|
|
197
|
+
client_assertion=self._signer.sign(),
|
|
198
|
+
request_options={"max_retries": 0},
|
|
199
|
+
)
|
|
200
|
+
except Exception as e:
|
|
201
|
+
if attempt >= _MAX_RETRIES or not _is_retryable(e):
|
|
202
|
+
raise
|
|
203
|
+
await asyncio.sleep(0.5 * 2**attempt)
|
|
204
|
+
attempt += 1
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/actions/types/actions_list_request_registry.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{pipedream-2.1.20 → pipedream-2.2.0}/src/pipedream/apps/types/apps_list_request_sort_direction.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|