├── src ├── knockapi │ ├── py.typed │ ├── types │ │ ├── shared_params │ │ │ ├── __init__.py │ │ │ └── condition.py │ │ ├── shared │ │ │ ├── __init__.py │ │ │ ├── page_info.py │ │ │ └── condition.py │ │ ├── schedules │ │ │ ├── __init__.py │ │ │ └── bulk_create_params.py │ │ ├── channels │ │ │ ├── __init__.py │ │ │ └── bulk_update_message_status_params.py │ │ ├── tenants │ │ │ ├── __init__.py │ │ │ ├── bulk_delete_params.py │ │ │ └── bulk_set_params.py │ │ ├── recipient.py │ │ ├── messages │ │ │ ├── batch_archive_response.py │ │ │ ├── batch_unarchive_response.py │ │ │ ├── batch_mark_as_read_response.py │ │ │ ├── batch_mark_as_seen_response.py │ │ │ ├── batch_mark_as_unread_response.py │ │ │ ├── batch_mark_as_unseen_response.py │ │ │ ├── batch_mark_as_interacted_response.py │ │ │ ├── batch_archive_params.py │ │ │ ├── batch_unarchive_params.py │ │ │ ├── batch_mark_as_read_params.py │ │ │ ├── batch_mark_as_seen_params.py │ │ │ ├── batch_get_content_params.py │ │ │ ├── batch_mark_as_unread_params.py │ │ │ ├── batch_mark_as_unseen_params.py │ │ │ ├── batch_mark_as_interacted_params.py │ │ │ └── __init__.py │ │ ├── schedule_create_response.py │ │ ├── schedule_delete_response.py │ │ ├── schedule_update_response.py │ │ ├── users │ │ │ ├── guide_mark_message_as_seen_response.py │ │ │ ├── guide_mark_message_as_archived_response.py │ │ │ ├── guide_mark_message_as_interacted_response.py │ │ │ ├── bulk_delete_params.py │ │ │ ├── feed_get_settings_response.py │ │ │ ├── bulk_identify_params.py │ │ │ ├── guide_get_channel_params.py │ │ │ ├── bulk_set_preferences_params.py │ │ │ ├── guide_mark_message_as_seen_params.py │ │ │ ├── guide_mark_message_as_archived_params.py │ │ │ ├── guide_mark_message_as_interacted_params.py │ │ │ ├── __init__.py │ │ │ └── feed_list_items_params.py │ │ ├── providers │ │ │ ├── ms_team_revoke_access_response.py │ │ │ ├── slack_revoke_access_response.py │ │ │ ├── slack_check_auth_params.py │ │ │ ├── slack_revoke_access_params.py │ │ │ ├── ms_team_check_auth_params.py │ │ │ ├── ms_team_revoke_access_params.py │ │ │ ├── slack_check_auth_response.py │ │ │ ├── ms_team_list_teams_response.py │ │ │ ├── ms_team_check_auth_response.py │ │ │ ├── slack_list_channels_response.py │ │ │ ├── ms_team_list_channels_params.py │ │ │ ├── ms_team_list_channels_response.py │ │ │ ├── __init__.py │ │ │ ├── slack_list_channels_params.py │ │ │ └── ms_team_list_teams_params.py │ │ ├── user_list_preferences_response.py │ │ ├── object_add_subscriptions_response.py │ │ ├── object_list_preferences_response.py │ │ ├── user_merge_params.py │ │ ├── object_delete_subscriptions_response.py │ │ ├── user_get_preferences_params.py │ │ ├── recipients │ │ │ ├── one_signal_channel_data_player_ids_only.py │ │ │ ├── preference_set_channel_setting.py │ │ │ ├── preference_set_channel_type_setting.py │ │ │ ├── inline_preference_set_request_param.py │ │ │ ├── push_channel_data_tokens_only_param.py │ │ │ ├── one_signal_channel_data_player_ids_only_param.py │ │ │ ├── preference_set_channel_setting_param.py │ │ │ ├── preference_set_channel_type_setting_param.py │ │ │ ├── aws_sns_push_channel_data_target_arns_only_param.py │ │ │ ├── subscription.py │ │ │ ├── discord_channel_data.py │ │ │ ├── push_channel_data_devices_only_param.py │ │ │ ├── discord_channel_data_param.py │ │ │ ├── slack_channel_data.py │ │ │ ├── aws_sns_push_channel_data_devices_only_param.py │ │ │ ├── slack_channel_data_param.py │ │ │ ├── inline_channel_data_request_param.py │ │ │ ├── preference_set_channel_types_param.py │ │ │ ├── preference_set_channel_types.py │ │ │ ├── ms_teams_channel_data.py │ │ │ ├── ms_teams_channel_data_param.py │ │ │ └── __init__.py │ │ ├── workflow_trigger_response.py │ │ ├── inline_tenant_request_param.py │ │ ├── message_mark_as_interacted_params.py │ │ ├── objects │ │ │ ├── bulk_delete_params.py │ │ │ ├── __init__.py │ │ │ ├── bulk_delete_subscriptions_params.py │ │ │ ├── bulk_add_subscriptions_params.py │ │ │ └── bulk_set_params.py │ │ ├── schedule_delete_params.py │ │ ├── integrations │ │ │ ├── census_custom_destination_response.py │ │ │ ├── hightouch_embedded_destination_response.py │ │ │ ├── __init__.py │ │ │ ├── census_custom_destination_params.py │ │ │ └── hightouch_embedded_destination_params.py │ │ ├── recipient_request_param.py │ │ ├── tenant_get_params.py │ │ ├── message_list_events_params.py │ │ ├── audience_list_members_response.py │ │ ├── message_list_delivery_logs_params.py │ │ ├── recipient_reference.py │ │ ├── recipient_reference_param.py │ │ ├── message_list_activities_params.py │ │ ├── tenant_list_params.py │ │ ├── object_delete_subscriptions_params.py │ │ ├── user_list_params.py │ │ ├── object_list_params.py │ │ ├── object_list_schedules_params.py │ │ ├── user_list_schedules_params.py │ │ ├── object_add_subscriptions_params.py │ │ ├── audience_remove_members_params.py │ │ ├── audience_add_members_params.py │ │ ├── schedule_list_params.py │ │ ├── object.py │ │ ├── user_list_subscriptions_params.py │ │ ├── audience_member.py │ │ ├── workflow_cancel_params.py │ │ ├── schedule_repeat_rule.py │ │ ├── schedule_repeat_rule_param.py │ │ ├── activity.py │ │ ├── object_set_params.py │ │ ├── object_list_subscriptions_params.py │ │ ├── user_set_channel_data_params.py │ │ ├── object_set_channel_data_params.py │ │ ├── inline_object_request_param.py │ │ ├── message_event.py │ │ ├── schedule_update_params.py │ │ ├── tenant_set_params.py │ │ ├── workflow_trigger_params.py │ │ ├── bulk_operation.py │ │ ├── schedule_create_params.py │ │ ├── schedule.py │ │ ├── user_update_params.py │ │ ├── message_delivery_log.py │ │ ├── user.py │ │ ├── tenant_request_param.py │ │ ├── inline_identify_user_request_param.py │ │ ├── tenant.py │ │ ├── message_list_params.py │ │ ├── user_list_messages_params.py │ │ └── object_list_messages_params.py │ ├── _version.py │ ├── lib │ │ └── .keep │ ├── _utils │ │ ├── _streams.py │ │ ├── _resources_proxy.py │ │ ├── _logs.py │ │ ├── _compat.py │ │ ├── _reflection.py │ │ ├── _sync.py │ │ ├── _proxy.py │ │ └── __init__.py │ ├── _constants.py │ ├── resources │ │ ├── objects │ │ │ └── __init__.py │ │ ├── tenants │ │ │ └── __init__.py │ │ ├── channels │ │ │ └── __init__.py │ │ ├── messages │ │ │ └── __init__.py │ │ ├── schedules │ │ │ └── __init__.py │ │ ├── providers │ │ │ └── __init__.py │ │ ├── integrations │ │ │ └── __init__.py │ │ └── users │ │ │ └── __init__.py │ ├── _resource.py │ └── __init__.py └── knock │ └── lib │ └── .keep ├── .python-version ├── Brewfile ├── .github ├── CODEOWNERS └── workflows │ ├── release-doctor.yml │ ├── publish-pypi.yml │ └── ci.yml ├── tests ├── sample_file.txt ├── __init__.py ├── api_resources │ ├── __init__.py │ ├── users │ │ └── __init__.py │ ├── channels │ │ └── __init__.py │ ├── messages │ │ └── __init__.py │ ├── objects │ │ └── __init__.py │ ├── providers │ │ └── __init__.py │ ├── schedules │ │ └── __init__.py │ ├── tenants │ │ └── __init__.py │ └── integrations │ │ └── __init__.py ├── test_utils │ ├── test_proxy.py │ └── test_typing.py ├── test_files.py ├── test_deepcopy.py └── test_extract_files.py ├── .release-please-manifest.json ├── .vscode └── settings.json ├── bin ├── publish-pypi └── check-release-environment ├── scripts ├── format ├── lint ├── bootstrap ├── utils │ └── upload-artifact.sh ├── mock └── test ├── .gitignore ├── examples └── .keep ├── .stats.yml ├── noxfile.py ├── .devcontainer ├── Dockerfile └── devcontainer.json ├── SECURITY.md ├── release-please-config.json └── requirements.lock /src/knockapi/py.typed: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.python-version: -------------------------------------------------------------------------------- 1 | 3.9.18 2 | -------------------------------------------------------------------------------- /Brewfile: -------------------------------------------------------------------------------- 1 | brew "rye" 2 | 3 | -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @knocklabs/product 2 | -------------------------------------------------------------------------------- /tests/sample_file.txt: -------------------------------------------------------------------------------- 1 | Hello, world! 2 | -------------------------------------------------------------------------------- /.release-please-manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | ".": "1.19.0" 3 | } -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "python.analysis.importFormat": "relative", 3 | } 4 | -------------------------------------------------------------------------------- /tests/__init__.py: -------------------------------------------------------------------------------- 1 | # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | -------------------------------------------------------------------------------- /tests/api_resources/__init__.py: -------------------------------------------------------------------------------- 1 | # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | -------------------------------------------------------------------------------- /tests/api_resources/users/__init__.py: -------------------------------------------------------------------------------- 1 | # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | -------------------------------------------------------------------------------- /tests/api_resources/channels/__init__.py: -------------------------------------------------------------------------------- 1 | # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | -------------------------------------------------------------------------------- /tests/api_resources/messages/__init__.py: -------------------------------------------------------------------------------- 1 | # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | -------------------------------------------------------------------------------- /tests/api_resources/objects/__init__.py: -------------------------------------------------------------------------------- 1 | # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | -------------------------------------------------------------------------------- /tests/api_resources/providers/__init__.py: -------------------------------------------------------------------------------- 1 | # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | -------------------------------------------------------------------------------- /tests/api_resources/schedules/__init__.py: -------------------------------------------------------------------------------- 1 | # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | -------------------------------------------------------------------------------- /tests/api_resources/tenants/__init__.py: -------------------------------------------------------------------------------- 1 | # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | -------------------------------------------------------------------------------- /tests/api_resources/integrations/__init__.py: -------------------------------------------------------------------------------- 1 | # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | -------------------------------------------------------------------------------- /bin/publish-pypi: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -eux 4 | mkdir -p dist 5 | rye build --clean 6 | rye publish --yes --token=$PYPI_TOKEN 7 | -------------------------------------------------------------------------------- /scripts/format: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | 5 | cd "$(dirname "$0")/.." 6 | 7 | echo "==> Running formatters" 8 | rye run format 9 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .prism.log 2 | _dev 3 | 4 | __pycache__ 5 | .mypy_cache 6 | 7 | dist 8 | 9 | .venv 10 | .idea 11 | 12 | .env 13 | .envrc 14 | codegen.log 15 | Brewfile.lock.json 16 | -------------------------------------------------------------------------------- /src/knockapi/types/shared_params/__init__.py: -------------------------------------------------------------------------------- 1 | # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | from .condition import Condition as Condition 4 | -------------------------------------------------------------------------------- /src/knockapi/_version.py: -------------------------------------------------------------------------------- 1 | # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | __title__ = "knockapi" 4 | __version__ = "1.19.0" # x-release-please-version 5 | -------------------------------------------------------------------------------- /scripts/lint: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | 5 | cd "$(dirname "$0")/.." 6 | 7 | echo "==> Running lints" 8 | rye run lint 9 | 10 | echo "==> Making sure it imports" 11 | rye run python -c 'import knockapi' 12 | -------------------------------------------------------------------------------- /src/knockapi/types/shared/__init__.py: -------------------------------------------------------------------------------- 1 | # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | from .condition import Condition as Condition 4 | from .page_info import PageInfo as PageInfo 5 | -------------------------------------------------------------------------------- /src/knockapi/types/schedules/__init__.py: -------------------------------------------------------------------------------- 1 | # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | from __future__ import annotations 4 | 5 | from .bulk_create_params import BulkCreateParams as BulkCreateParams 6 | -------------------------------------------------------------------------------- /src/knock/lib/.keep: -------------------------------------------------------------------------------- 1 | File generated from our OpenAPI spec by Stainless. 2 | 3 | This directory can be used to store custom files to expand the SDK. 4 | It is ignored by Stainless code generation and its content (other than this keep file) won't be touched. -------------------------------------------------------------------------------- /src/knockapi/lib/.keep: -------------------------------------------------------------------------------- 1 | File generated from our OpenAPI spec by Stainless. 2 | 3 | This directory can be used to store custom files to expand the SDK. 4 | It is ignored by Stainless code generation and its content (other than this keep file) won't be touched. -------------------------------------------------------------------------------- /examples/.keep: -------------------------------------------------------------------------------- 1 | File generated from our OpenAPI spec by Stainless. 2 | 3 | This directory can be used to store example files demonstrating usage of this SDK. 4 | It is ignored by Stainless code generation and its content (other than this keep file) won't be touched. -------------------------------------------------------------------------------- /src/knockapi/types/channels/__init__.py: -------------------------------------------------------------------------------- 1 | # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | from __future__ import annotations 4 | 5 | from .bulk_update_message_status_params import BulkUpdateMessageStatusParams as BulkUpdateMessageStatusParams 6 | -------------------------------------------------------------------------------- /.stats.yml: -------------------------------------------------------------------------------- 1 | configured_endpoints: 90 2 | openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/knock%2Fknock-ce72fff9b44a47ab7e0425e496f09c61cde5b4258feb20cb5dbef6fa615a57e4.yml 3 | openapi_spec_hash: 3054ea299cf43dc89b68266818fecfe4 4 | config_hash: 2b42d138d85c524e65fa7e205d36cc4a 5 | -------------------------------------------------------------------------------- /src/knockapi/types/tenants/__init__.py: -------------------------------------------------------------------------------- 1 | # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | from __future__ import annotations 4 | 5 | from .bulk_set_params import BulkSetParams as BulkSetParams 6 | from .bulk_delete_params import BulkDeleteParams as BulkDeleteParams 7 | -------------------------------------------------------------------------------- /noxfile.py: -------------------------------------------------------------------------------- 1 | import nox 2 | 3 | 4 | @nox.session(reuse_venv=True, name="test-pydantic-v1") 5 | def test_pydantic_v1(session: nox.Session) -> None: 6 | session.install("-r", "requirements-dev.lock") 7 | session.install("pydantic<2") 8 | 9 | session.run("pytest", "--showlocals", "--ignore=tests/functional", *session.posargs) 10 | -------------------------------------------------------------------------------- /src/knockapi/types/recipient.py: -------------------------------------------------------------------------------- 1 | # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | from typing import Union 4 | from typing_extensions import TypeAlias 5 | 6 | from .user import User 7 | from .object import Object 8 | 9 | __all__ = ["Recipient"] 10 | 11 | Recipient: TypeAlias = Union[User, Object] 12 | -------------------------------------------------------------------------------- /src/knockapi/types/messages/batch_archive_response.py: -------------------------------------------------------------------------------- 1 | # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | from typing import List 4 | from typing_extensions import TypeAlias 5 | 6 | from ..message import Message 7 | 8 | __all__ = ["BatchArchiveResponse"] 9 | 10 | BatchArchiveResponse: TypeAlias = List[Message] 11 | -------------------------------------------------------------------------------- /src/knockapi/types/schedule_create_response.py: -------------------------------------------------------------------------------- 1 | # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | from typing import List 4 | from typing_extensions import TypeAlias 5 | 6 | from .schedule import Schedule 7 | 8 | __all__ = ["ScheduleCreateResponse"] 9 | 10 | ScheduleCreateResponse: TypeAlias = List[Schedule] 11 | -------------------------------------------------------------------------------- /src/knockapi/types/schedule_delete_response.py: -------------------------------------------------------------------------------- 1 | # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | from typing import List 4 | from typing_extensions import TypeAlias 5 | 6 | from .schedule import Schedule 7 | 8 | __all__ = ["ScheduleDeleteResponse"] 9 | 10 | ScheduleDeleteResponse: TypeAlias = List[Schedule] 11 | -------------------------------------------------------------------------------- /src/knockapi/types/schedule_update_response.py: -------------------------------------------------------------------------------- 1 | # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | from typing import List 4 | from typing_extensions import TypeAlias 5 | 6 | from .schedule import Schedule 7 | 8 | __all__ = ["ScheduleUpdateResponse"] 9 | 10 | ScheduleUpdateResponse: TypeAlias = List[Schedule] 11 | -------------------------------------------------------------------------------- /src/knockapi/types/messages/batch_unarchive_response.py: -------------------------------------------------------------------------------- 1 | # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | from typing import List 4 | from typing_extensions import TypeAlias 5 | 6 | from ..message import Message 7 | 8 | __all__ = ["BatchUnarchiveResponse"] 9 | 10 | BatchUnarchiveResponse: TypeAlias = List[Message] 11 | -------------------------------------------------------------------------------- /src/knockapi/_utils/_streams.py: -------------------------------------------------------------------------------- 1 | from typing import Any 2 | from typing_extensions import Iterator, AsyncIterator 3 | 4 | 5 | def consume_sync_iterator(iterator: Iterator[Any]) -> None: 6 | for _ in iterator: 7 | ... 8 | 9 | 10 | async def consume_async_iterator(iterator: AsyncIterator[Any]) -> None: 11 | async for _ in iterator: 12 | ... 13 | -------------------------------------------------------------------------------- /src/knockapi/types/messages/batch_mark_as_read_response.py: -------------------------------------------------------------------------------- 1 | # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | from typing import List 4 | from typing_extensions import TypeAlias 5 | 6 | from ..message import Message 7 | 8 | __all__ = ["BatchMarkAsReadResponse"] 9 | 10 | BatchMarkAsReadResponse: TypeAlias = List[Message] 11 | -------------------------------------------------------------------------------- /src/knockapi/types/messages/batch_mark_as_seen_response.py: -------------------------------------------------------------------------------- 1 | # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | from typing import List 4 | from typing_extensions import TypeAlias 5 | 6 | from ..message import Message 7 | 8 | __all__ = ["BatchMarkAsSeenResponse"] 9 | 10 | BatchMarkAsSeenResponse: TypeAlias = List[Message] 11 | -------------------------------------------------------------------------------- /src/knockapi/types/messages/batch_mark_as_unread_response.py: -------------------------------------------------------------------------------- 1 | # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | from typing import List 4 | from typing_extensions import TypeAlias 5 | 6 | from ..message import Message 7 | 8 | __all__ = ["BatchMarkAsUnreadResponse"] 9 | 10 | BatchMarkAsUnreadResponse: TypeAlias = List[Message] 11 | -------------------------------------------------------------------------------- /src/knockapi/types/messages/batch_mark_as_unseen_response.py: -------------------------------------------------------------------------------- 1 | # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | from typing import List 4 | from typing_extensions import TypeAlias 5 | 6 | from ..message import Message 7 | 8 | __all__ = ["BatchMarkAsUnseenResponse"] 9 | 10 | BatchMarkAsUnseenResponse: TypeAlias = List[Message] 11 | -------------------------------------------------------------------------------- /src/knockapi/types/users/guide_mark_message_as_seen_response.py: -------------------------------------------------------------------------------- 1 | # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | from ..._models import BaseModel 4 | 5 | __all__ = ["GuideMarkMessageAsSeenResponse"] 6 | 7 | 8 | class GuideMarkMessageAsSeenResponse(BaseModel): 9 | status: str 10 | """The status of a guide's action.""" 11 | -------------------------------------------------------------------------------- /.devcontainer/Dockerfile: -------------------------------------------------------------------------------- 1 | ARG VARIANT="3.9" 2 | FROM mcr.microsoft.com/vscode/devcontainers/python:0-${VARIANT} 3 | 4 | USER vscode 5 | 6 | RUN curl -sSf https://rye.astral.sh/get | RYE_VERSION="0.44.0" RYE_INSTALL_OPTION="--yes" bash 7 | ENV PATH=/home/vscode/.rye/shims:$PATH 8 | 9 | RUN echo "[[ -d .venv ]] && source .venv/bin/activate || export PATH=\$PATH" >> /home/vscode/.bashrc 10 | -------------------------------------------------------------------------------- /src/knockapi/types/messages/batch_mark_as_interacted_response.py: -------------------------------------------------------------------------------- 1 | # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | from typing import List 4 | from typing_extensions import TypeAlias 5 | 6 | from ..message import Message 7 | 8 | __all__ = ["BatchMarkAsInteractedResponse"] 9 | 10 | BatchMarkAsInteractedResponse: TypeAlias = List[Message] 11 | -------------------------------------------------------------------------------- /src/knockapi/types/users/guide_mark_message_as_archived_response.py: -------------------------------------------------------------------------------- 1 | # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | from ..._models import BaseModel 4 | 5 | __all__ = ["GuideMarkMessageAsArchivedResponse"] 6 | 7 | 8 | class GuideMarkMessageAsArchivedResponse(BaseModel): 9 | status: str 10 | """The status of a guide's action.""" 11 | -------------------------------------------------------------------------------- /src/knockapi/types/users/guide_mark_message_as_interacted_response.py: -------------------------------------------------------------------------------- 1 | # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | from ..._models import BaseModel 4 | 5 | __all__ = ["GuideMarkMessageAsInteractedResponse"] 6 | 7 | 8 | class GuideMarkMessageAsInteractedResponse(BaseModel): 9 | status: str 10 | """The status of a guide's action.""" 11 | -------------------------------------------------------------------------------- /src/knockapi/types/providers/ms_team_revoke_access_response.py: -------------------------------------------------------------------------------- 1 | # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | from typing import Optional 4 | 5 | from ..._models import BaseModel 6 | 7 | __all__ = ["MsTeamRevokeAccessResponse"] 8 | 9 | 10 | class MsTeamRevokeAccessResponse(BaseModel): 11 | ok: Optional[str] = None 12 | """OK response.""" 13 | -------------------------------------------------------------------------------- /src/knockapi/types/providers/slack_revoke_access_response.py: -------------------------------------------------------------------------------- 1 | # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | from typing import Optional 4 | 5 | from ..._models import BaseModel 6 | 7 | __all__ = ["SlackRevokeAccessResponse"] 8 | 9 | 10 | class SlackRevokeAccessResponse(BaseModel): 11 | ok: Optional[str] = None 12 | """OK response.""" 13 | -------------------------------------------------------------------------------- /src/knockapi/types/user_list_preferences_response.py: -------------------------------------------------------------------------------- 1 | # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | from typing import List 4 | from typing_extensions import TypeAlias 5 | 6 | from .recipients.preference_set import PreferenceSet 7 | 8 | __all__ = ["UserListPreferencesResponse"] 9 | 10 | UserListPreferencesResponse: TypeAlias = List[PreferenceSet] 11 | -------------------------------------------------------------------------------- /src/knockapi/types/object_add_subscriptions_response.py: -------------------------------------------------------------------------------- 1 | # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | from typing import List 4 | from typing_extensions import TypeAlias 5 | 6 | from .recipients.subscription import Subscription 7 | 8 | __all__ = ["ObjectAddSubscriptionsResponse"] 9 | 10 | ObjectAddSubscriptionsResponse: TypeAlias = List[Subscription] 11 | -------------------------------------------------------------------------------- /src/knockapi/types/object_list_preferences_response.py: -------------------------------------------------------------------------------- 1 | # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | from typing import List 4 | from typing_extensions import TypeAlias 5 | 6 | from .recipients.preference_set import PreferenceSet 7 | 8 | __all__ = ["ObjectListPreferencesResponse"] 9 | 10 | ObjectListPreferencesResponse: TypeAlias = List[PreferenceSet] 11 | -------------------------------------------------------------------------------- /src/knockapi/types/user_merge_params.py: -------------------------------------------------------------------------------- 1 | # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | from __future__ import annotations 4 | 5 | from typing_extensions import Required, TypedDict 6 | 7 | __all__ = ["UserMergeParams"] 8 | 9 | 10 | class UserMergeParams(TypedDict, total=False): 11 | from_user_id: Required[str] 12 | """The user ID to merge from.""" 13 | -------------------------------------------------------------------------------- /src/knockapi/types/object_delete_subscriptions_response.py: -------------------------------------------------------------------------------- 1 | # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | from typing import List 4 | from typing_extensions import TypeAlias 5 | 6 | from .recipients.subscription import Subscription 7 | 8 | __all__ = ["ObjectDeleteSubscriptionsResponse"] 9 | 10 | ObjectDeleteSubscriptionsResponse: TypeAlias = List[Subscription] 11 | -------------------------------------------------------------------------------- /src/knockapi/types/user_get_preferences_params.py: -------------------------------------------------------------------------------- 1 | # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | from __future__ import annotations 4 | 5 | from typing_extensions import TypedDict 6 | 7 | __all__ = ["UserGetPreferencesParams"] 8 | 9 | 10 | class UserGetPreferencesParams(TypedDict, total=False): 11 | tenant: str 12 | """The unique identifier for the tenant.""" 13 | -------------------------------------------------------------------------------- /src/knockapi/types/recipients/one_signal_channel_data_player_ids_only.py: -------------------------------------------------------------------------------- 1 | # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | from typing import List 4 | 5 | from ..._models import BaseModel 6 | 7 | __all__ = ["OneSignalChannelDataPlayerIDsOnly"] 8 | 9 | 10 | class OneSignalChannelDataPlayerIDsOnly(BaseModel): 11 | player_ids: List[str] 12 | """A list of OneSignal player IDs.""" 13 | -------------------------------------------------------------------------------- /src/knockapi/types/workflow_trigger_response.py: -------------------------------------------------------------------------------- 1 | # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | from .._models import BaseModel 4 | 5 | __all__ = ["WorkflowTriggerResponse"] 6 | 7 | 8 | class WorkflowTriggerResponse(BaseModel): 9 | workflow_run_id: str 10 | """ 11 | This value allows you to track individual messages associated with this trigger 12 | request. 13 | """ 14 | -------------------------------------------------------------------------------- /src/knockapi/types/inline_tenant_request_param.py: -------------------------------------------------------------------------------- 1 | # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | from __future__ import annotations 4 | 5 | from typing import Union 6 | from typing_extensions import TypeAlias 7 | 8 | from .tenant_request_param import TenantRequestParam 9 | 10 | __all__ = ["InlineTenantRequestParam"] 11 | 12 | InlineTenantRequestParam: TypeAlias = Union[str, TenantRequestParam] 13 | -------------------------------------------------------------------------------- /src/knockapi/types/users/bulk_delete_params.py: -------------------------------------------------------------------------------- 1 | # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | from __future__ import annotations 4 | 5 | from typing_extensions import Required, TypedDict 6 | 7 | from ..._types import SequenceNotStr 8 | 9 | __all__ = ["BulkDeleteParams"] 10 | 11 | 12 | class BulkDeleteParams(TypedDict, total=False): 13 | user_ids: Required[SequenceNotStr[str]] 14 | """A list of user IDs.""" 15 | -------------------------------------------------------------------------------- /src/knockapi/types/message_mark_as_interacted_params.py: -------------------------------------------------------------------------------- 1 | # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | from __future__ import annotations 4 | 5 | from typing import Dict 6 | from typing_extensions import TypedDict 7 | 8 | __all__ = ["MessageMarkAsInteractedParams"] 9 | 10 | 11 | class MessageMarkAsInteractedParams(TypedDict, total=False): 12 | metadata: Dict[str, object] 13 | """Metadata about the interaction.""" 14 | -------------------------------------------------------------------------------- /src/knockapi/types/objects/bulk_delete_params.py: -------------------------------------------------------------------------------- 1 | # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | from __future__ import annotations 4 | 5 | from typing_extensions import Required, TypedDict 6 | 7 | from ..._types import SequenceNotStr 8 | 9 | __all__ = ["BulkDeleteParams"] 10 | 11 | 12 | class BulkDeleteParams(TypedDict, total=False): 13 | object_ids: Required[SequenceNotStr[str]] 14 | """List of object IDs to delete.""" 15 | -------------------------------------------------------------------------------- /src/knockapi/types/providers/slack_check_auth_params.py: -------------------------------------------------------------------------------- 1 | # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | from __future__ import annotations 4 | 5 | from typing_extensions import Required, TypedDict 6 | 7 | __all__ = ["SlackCheckAuthParams"] 8 | 9 | 10 | class SlackCheckAuthParams(TypedDict, total=False): 11 | access_token_object: Required[str] 12 | """A JSON encoded string containing the access token object reference.""" 13 | -------------------------------------------------------------------------------- /src/knockapi/types/schedule_delete_params.py: -------------------------------------------------------------------------------- 1 | # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | from __future__ import annotations 4 | 5 | from typing_extensions import Required, TypedDict 6 | 7 | from .._types import SequenceNotStr 8 | 9 | __all__ = ["ScheduleDeleteParams"] 10 | 11 | 12 | class ScheduleDeleteParams(TypedDict, total=False): 13 | schedule_ids: Required[SequenceNotStr[str]] 14 | """A list of schedule IDs.""" 15 | -------------------------------------------------------------------------------- /src/knockapi/types/recipients/preference_set_channel_setting.py: -------------------------------------------------------------------------------- 1 | # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | from typing import List 4 | 5 | from ..._models import BaseModel 6 | from ..shared.condition import Condition 7 | 8 | __all__ = ["PreferenceSetChannelSetting"] 9 | 10 | 11 | class PreferenceSetChannelSetting(BaseModel): 12 | conditions: List[Condition] 13 | """A list of conditions to apply to a specific channel.""" 14 | -------------------------------------------------------------------------------- /src/knockapi/types/tenants/bulk_delete_params.py: -------------------------------------------------------------------------------- 1 | # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | from __future__ import annotations 4 | 5 | from typing_extensions import Required, TypedDict 6 | 7 | from ..._types import SequenceNotStr 8 | 9 | __all__ = ["BulkDeleteParams"] 10 | 11 | 12 | class BulkDeleteParams(TypedDict, total=False): 13 | tenant_ids: Required[SequenceNotStr[str]] 14 | """The IDs of the tenants to delete.""" 15 | -------------------------------------------------------------------------------- /src/knockapi/types/providers/slack_revoke_access_params.py: -------------------------------------------------------------------------------- 1 | # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | from __future__ import annotations 4 | 5 | from typing_extensions import Required, TypedDict 6 | 7 | __all__ = ["SlackRevokeAccessParams"] 8 | 9 | 10 | class SlackRevokeAccessParams(TypedDict, total=False): 11 | access_token_object: Required[str] 12 | """A JSON encoded string containing the access token object reference.""" 13 | -------------------------------------------------------------------------------- /src/knockapi/types/providers/ms_team_check_auth_params.py: -------------------------------------------------------------------------------- 1 | # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | from __future__ import annotations 4 | 5 | from typing_extensions import Required, TypedDict 6 | 7 | __all__ = ["MsTeamCheckAuthParams"] 8 | 9 | 10 | class MsTeamCheckAuthParams(TypedDict, total=False): 11 | ms_teams_tenant_object: Required[str] 12 | """A JSON encoded string containing the Microsoft Teams tenant object reference.""" 13 | -------------------------------------------------------------------------------- /src/knockapi/types/recipients/preference_set_channel_type_setting.py: -------------------------------------------------------------------------------- 1 | # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | from typing import List 4 | 5 | from ..._models import BaseModel 6 | from ..shared.condition import Condition 7 | 8 | __all__ = ["PreferenceSetChannelTypeSetting"] 9 | 10 | 11 | class PreferenceSetChannelTypeSetting(BaseModel): 12 | conditions: List[Condition] 13 | """A list of conditions to apply to a channel type.""" 14 | -------------------------------------------------------------------------------- /src/knockapi/types/messages/batch_archive_params.py: -------------------------------------------------------------------------------- 1 | # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | from __future__ import annotations 4 | 5 | from typing_extensions import Required, TypedDict 6 | 7 | from ..._types import SequenceNotStr 8 | 9 | __all__ = ["BatchArchiveParams"] 10 | 11 | 12 | class BatchArchiveParams(TypedDict, total=False): 13 | message_ids: Required[SequenceNotStr[str]] 14 | """The message IDs to update the status of.""" 15 | -------------------------------------------------------------------------------- /src/knockapi/types/recipients/inline_preference_set_request_param.py: -------------------------------------------------------------------------------- 1 | # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | from __future__ import annotations 4 | 5 | from typing import Dict 6 | from typing_extensions import TypeAlias 7 | 8 | from .preference_set_request_param import PreferenceSetRequestParam 9 | 10 | __all__ = ["InlinePreferenceSetRequestParam"] 11 | 12 | InlinePreferenceSetRequestParam: TypeAlias = Dict[str, PreferenceSetRequestParam] 13 | -------------------------------------------------------------------------------- /src/knockapi/types/messages/batch_unarchive_params.py: -------------------------------------------------------------------------------- 1 | # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | from __future__ import annotations 4 | 5 | from typing_extensions import Required, TypedDict 6 | 7 | from ..._types import SequenceNotStr 8 | 9 | __all__ = ["BatchUnarchiveParams"] 10 | 11 | 12 | class BatchUnarchiveParams(TypedDict, total=False): 13 | message_ids: Required[SequenceNotStr[str]] 14 | """The message IDs to update the status of.""" 15 | -------------------------------------------------------------------------------- /src/knockapi/types/providers/ms_team_revoke_access_params.py: -------------------------------------------------------------------------------- 1 | # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | from __future__ import annotations 4 | 5 | from typing_extensions import Required, TypedDict 6 | 7 | __all__ = ["MsTeamRevokeAccessParams"] 8 | 9 | 10 | class MsTeamRevokeAccessParams(TypedDict, total=False): 11 | ms_teams_tenant_object: Required[str] 12 | """A JSON encoded string containing the Microsoft Teams tenant object reference.""" 13 | -------------------------------------------------------------------------------- /src/knockapi/types/messages/batch_mark_as_read_params.py: -------------------------------------------------------------------------------- 1 | # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | from __future__ import annotations 4 | 5 | from typing_extensions import Required, TypedDict 6 | 7 | from ..._types import SequenceNotStr 8 | 9 | __all__ = ["BatchMarkAsReadParams"] 10 | 11 | 12 | class BatchMarkAsReadParams(TypedDict, total=False): 13 | message_ids: Required[SequenceNotStr[str]] 14 | """The message IDs to update the status of.""" 15 | -------------------------------------------------------------------------------- /src/knockapi/types/messages/batch_mark_as_seen_params.py: -------------------------------------------------------------------------------- 1 | # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | from __future__ import annotations 4 | 5 | from typing_extensions import Required, TypedDict 6 | 7 | from ..._types import SequenceNotStr 8 | 9 | __all__ = ["BatchMarkAsSeenParams"] 10 | 11 | 12 | class BatchMarkAsSeenParams(TypedDict, total=False): 13 | message_ids: Required[SequenceNotStr[str]] 14 | """The message IDs to update the status of.""" 15 | -------------------------------------------------------------------------------- /src/knockapi/types/messages/batch_get_content_params.py: -------------------------------------------------------------------------------- 1 | # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | from __future__ import annotations 4 | 5 | from typing_extensions import Required, TypedDict 6 | 7 | from ..._types import SequenceNotStr 8 | 9 | __all__ = ["BatchGetContentParams"] 10 | 11 | 12 | class BatchGetContentParams(TypedDict, total=False): 13 | message_ids: Required[SequenceNotStr[str]] 14 | """The IDs of the messages to fetch contents of.""" 15 | -------------------------------------------------------------------------------- /src/knockapi/types/objects/__init__.py: -------------------------------------------------------------------------------- 1 | # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | from __future__ import annotations 4 | 5 | from .bulk_set_params import BulkSetParams as BulkSetParams 6 | from .bulk_delete_params import BulkDeleteParams as BulkDeleteParams 7 | from .bulk_add_subscriptions_params import BulkAddSubscriptionsParams as BulkAddSubscriptionsParams 8 | from .bulk_delete_subscriptions_params import BulkDeleteSubscriptionsParams as BulkDeleteSubscriptionsParams 9 | -------------------------------------------------------------------------------- /src/knockapi/types/messages/batch_mark_as_unread_params.py: -------------------------------------------------------------------------------- 1 | # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | from __future__ import annotations 4 | 5 | from typing_extensions import Required, TypedDict 6 | 7 | from ..._types import SequenceNotStr 8 | 9 | __all__ = ["BatchMarkAsUnreadParams"] 10 | 11 | 12 | class BatchMarkAsUnreadParams(TypedDict, total=False): 13 | message_ids: Required[SequenceNotStr[str]] 14 | """The message IDs to update the status of.""" 15 | -------------------------------------------------------------------------------- /src/knockapi/types/messages/batch_mark_as_unseen_params.py: -------------------------------------------------------------------------------- 1 | # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | from __future__ import annotations 4 | 5 | from typing_extensions import Required, TypedDict 6 | 7 | from ..._types import SequenceNotStr 8 | 9 | __all__ = ["BatchMarkAsUnseenParams"] 10 | 11 | 12 | class BatchMarkAsUnseenParams(TypedDict, total=False): 13 | message_ids: Required[SequenceNotStr[str]] 14 | """The message IDs to update the status of.""" 15 | -------------------------------------------------------------------------------- /src/knockapi/types/integrations/census_custom_destination_response.py: -------------------------------------------------------------------------------- 1 | # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | from typing import Dict, Optional 4 | 5 | from ..._models import BaseModel 6 | 7 | __all__ = ["CensusCustomDestinationResponse"] 8 | 9 | 10 | class CensusCustomDestinationResponse(BaseModel): 11 | id: Optional[str] = None 12 | """The request ID.""" 13 | 14 | result: Optional[Dict[str, object]] = None 15 | """The result of the RPC call.""" 16 | -------------------------------------------------------------------------------- /src/knockapi/types/recipients/push_channel_data_tokens_only_param.py: -------------------------------------------------------------------------------- 1 | # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | from __future__ import annotations 4 | 5 | from typing_extensions import Required, TypedDict 6 | 7 | from ..._types import SequenceNotStr 8 | 9 | __all__ = ["PushChannelDataTokensOnlyParam"] 10 | 11 | 12 | class PushChannelDataTokensOnlyParam(TypedDict, total=False): 13 | tokens: Required[SequenceNotStr[str]] 14 | """A list of push channel tokens.""" 15 | -------------------------------------------------------------------------------- /src/knockapi/types/users/feed_get_settings_response.py: -------------------------------------------------------------------------------- 1 | # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | from ..._models import BaseModel 4 | 5 | __all__ = ["FeedGetSettingsResponse", "Features"] 6 | 7 | 8 | class Features(BaseModel): 9 | branding_required: bool 10 | """Whether branding is required for the user's feed.""" 11 | 12 | 13 | class FeedGetSettingsResponse(BaseModel): 14 | features: Features 15 | """Features configuration for the user's feed.""" 16 | -------------------------------------------------------------------------------- /src/knockapi/types/integrations/hightouch_embedded_destination_response.py: -------------------------------------------------------------------------------- 1 | # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | from typing import Dict, Optional 4 | 5 | from ..._models import BaseModel 6 | 7 | __all__ = ["HightouchEmbeddedDestinationResponse"] 8 | 9 | 10 | class HightouchEmbeddedDestinationResponse(BaseModel): 11 | id: Optional[str] = None 12 | """The request ID.""" 13 | 14 | result: Optional[Dict[str, object]] = None 15 | """The result of the RPC call.""" 16 | -------------------------------------------------------------------------------- /src/knockapi/_constants.py: -------------------------------------------------------------------------------- 1 | # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | import httpx 4 | 5 | RAW_RESPONSE_HEADER = "X-Stainless-Raw-Response" 6 | OVERRIDE_CAST_TO_HEADER = "____stainless_override_cast_to" 7 | 8 | # default timeout is 1 minute 9 | DEFAULT_TIMEOUT = httpx.Timeout(timeout=60, connect=5.0) 10 | DEFAULT_MAX_RETRIES = 2 11 | DEFAULT_CONNECTION_LIMITS = httpx.Limits(max_connections=100, max_keepalive_connections=20) 12 | 13 | INITIAL_RETRY_DELAY = 0.5 14 | MAX_RETRY_DELAY = 8.0 15 | -------------------------------------------------------------------------------- /src/knockapi/types/recipients/one_signal_channel_data_player_ids_only_param.py: -------------------------------------------------------------------------------- 1 | # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | from __future__ import annotations 4 | 5 | from typing_extensions import Required, TypedDict 6 | 7 | from ..._types import SequenceNotStr 8 | 9 | __all__ = ["OneSignalChannelDataPlayerIDsOnlyParam"] 10 | 11 | 12 | class OneSignalChannelDataPlayerIDsOnlyParam(TypedDict, total=False): 13 | player_ids: Required[SequenceNotStr[str]] 14 | """A list of OneSignal player IDs.""" 15 | -------------------------------------------------------------------------------- /src/knockapi/types/tenants/bulk_set_params.py: -------------------------------------------------------------------------------- 1 | # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | from __future__ import annotations 4 | 5 | from typing_extensions import Required, TypedDict 6 | 7 | from ..._types import SequenceNotStr 8 | from ..inline_tenant_request_param import InlineTenantRequestParam 9 | 10 | __all__ = ["BulkSetParams"] 11 | 12 | 13 | class BulkSetParams(TypedDict, total=False): 14 | tenants: Required[SequenceNotStr[InlineTenantRequestParam]] 15 | """The tenants to be upserted.""" 16 | -------------------------------------------------------------------------------- /src/knockapi/types/users/bulk_identify_params.py: -------------------------------------------------------------------------------- 1 | # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | from __future__ import annotations 4 | 5 | from typing import Iterable 6 | from typing_extensions import Required, TypedDict 7 | 8 | from ..inline_identify_user_request_param import InlineIdentifyUserRequestParam 9 | 10 | __all__ = ["BulkIdentifyParams"] 11 | 12 | 13 | class BulkIdentifyParams(TypedDict, total=False): 14 | users: Required[Iterable[InlineIdentifyUserRequestParam]] 15 | """A list of users.""" 16 | -------------------------------------------------------------------------------- /src/knockapi/types/recipient_request_param.py: -------------------------------------------------------------------------------- 1 | # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | from __future__ import annotations 4 | 5 | from typing import Union 6 | from typing_extensions import TypeAlias 7 | 8 | from .inline_object_request_param import InlineObjectRequestParam 9 | from .inline_identify_user_request_param import InlineIdentifyUserRequestParam 10 | 11 | __all__ = ["RecipientRequestParam"] 12 | 13 | RecipientRequestParam: TypeAlias = Union[str, InlineIdentifyUserRequestParam, InlineObjectRequestParam] 14 | -------------------------------------------------------------------------------- /bin/check-release-environment: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | errors=() 4 | 5 | if [ -z "${PYPI_TOKEN}" ]; then 6 | errors+=("The PYPI_TOKEN secret has not been set. Please set it in either this repository's secrets or your organization secrets.") 7 | fi 8 | 9 | lenErrors=${#errors[@]} 10 | 11 | if [[ lenErrors -gt 0 ]]; then 12 | echo -e "Found the following errors in the release environment:\n" 13 | 14 | for error in "${errors[@]}"; do 15 | echo -e "- $error\n" 16 | done 17 | 18 | exit 1 19 | fi 20 | 21 | echo "The environment is ready to push releases!" 22 | -------------------------------------------------------------------------------- /src/knockapi/types/tenant_get_params.py: -------------------------------------------------------------------------------- 1 | # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | from __future__ import annotations 4 | 5 | from typing_extensions import TypedDict 6 | 7 | __all__ = ["TenantGetParams"] 8 | 9 | 10 | class TenantGetParams(TypedDict, total=False): 11 | resolve_full_preference_settings: bool 12 | """ 13 | When true, merges environment-level default preferences into the tenant's 14 | `settings.preference_set` field before returning the response. Defaults to 15 | false. 16 | """ 17 | -------------------------------------------------------------------------------- /src/knockapi/types/message_list_events_params.py: -------------------------------------------------------------------------------- 1 | # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | from __future__ import annotations 4 | 5 | from typing_extensions import TypedDict 6 | 7 | __all__ = ["MessageListEventsParams"] 8 | 9 | 10 | class MessageListEventsParams(TypedDict, total=False): 11 | after: str 12 | """The cursor to fetch entries after.""" 13 | 14 | before: str 15 | """The cursor to fetch entries before.""" 16 | 17 | page_size: int 18 | """The number of items per page (defaults to 50).""" 19 | -------------------------------------------------------------------------------- /src/knockapi/types/audience_list_members_response.py: -------------------------------------------------------------------------------- 1 | # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | from typing import List 4 | 5 | from .._models import BaseModel 6 | from .audience_member import AudienceMember 7 | from .shared.page_info import PageInfo 8 | 9 | __all__ = ["AudienceListMembersResponse"] 10 | 11 | 12 | class AudienceListMembersResponse(BaseModel): 13 | entries: List[AudienceMember] 14 | """A list of audience members.""" 15 | 16 | page_info: PageInfo 17 | """Pagination information for a list of resources.""" 18 | -------------------------------------------------------------------------------- /src/knockapi/types/message_list_delivery_logs_params.py: -------------------------------------------------------------------------------- 1 | # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | from __future__ import annotations 4 | 5 | from typing_extensions import TypedDict 6 | 7 | __all__ = ["MessageListDeliveryLogsParams"] 8 | 9 | 10 | class MessageListDeliveryLogsParams(TypedDict, total=False): 11 | after: str 12 | """The cursor to fetch entries after.""" 13 | 14 | before: str 15 | """The cursor to fetch entries before.""" 16 | 17 | page_size: int 18 | """The number of items per page (defaults to 50).""" 19 | -------------------------------------------------------------------------------- /src/knockapi/types/recipients/preference_set_channel_setting_param.py: -------------------------------------------------------------------------------- 1 | # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | from __future__ import annotations 4 | 5 | from typing import Iterable 6 | from typing_extensions import Required, TypedDict 7 | 8 | from ..shared_params.condition import Condition 9 | 10 | __all__ = ["PreferenceSetChannelSettingParam"] 11 | 12 | 13 | class PreferenceSetChannelSettingParam(TypedDict, total=False): 14 | conditions: Required[Iterable[Condition]] 15 | """A list of conditions to apply to a specific channel.""" 16 | -------------------------------------------------------------------------------- /src/knockapi/types/recipients/preference_set_channel_type_setting_param.py: -------------------------------------------------------------------------------- 1 | # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | from __future__ import annotations 4 | 5 | from typing import Iterable 6 | from typing_extensions import Required, TypedDict 7 | 8 | from ..shared_params.condition import Condition 9 | 10 | __all__ = ["PreferenceSetChannelTypeSettingParam"] 11 | 12 | 13 | class PreferenceSetChannelTypeSettingParam(TypedDict, total=False): 14 | conditions: Required[Iterable[Condition]] 15 | """A list of conditions to apply to a channel type.""" 16 | -------------------------------------------------------------------------------- /src/knockapi/types/users/guide_get_channel_params.py: -------------------------------------------------------------------------------- 1 | # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | from __future__ import annotations 4 | 5 | from typing_extensions import TypedDict 6 | 7 | __all__ = ["GuideGetChannelParams"] 8 | 9 | 10 | class GuideGetChannelParams(TypedDict, total=False): 11 | data: str 12 | """The data (JSON encoded object) to use for targeting and rendering guides.""" 13 | 14 | tenant: str 15 | """The tenant ID to use for targeting and rendering guides.""" 16 | 17 | type: str 18 | """The type of guides to filter by.""" 19 | -------------------------------------------------------------------------------- /src/knockapi/types/recipient_reference.py: -------------------------------------------------------------------------------- 1 | # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | from typing import Union, Optional 4 | from typing_extensions import TypeAlias 5 | 6 | from .._models import BaseModel 7 | 8 | __all__ = ["RecipientReference", "ObjectReference"] 9 | 10 | 11 | class ObjectReference(BaseModel): 12 | id: Optional[str] = None 13 | """An identifier for the recipient object.""" 14 | 15 | collection: Optional[str] = None 16 | """The collection the recipient object belongs to.""" 17 | 18 | 19 | RecipientReference: TypeAlias = Union[str, ObjectReference] 20 | -------------------------------------------------------------------------------- /src/knockapi/types/recipient_reference_param.py: -------------------------------------------------------------------------------- 1 | # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | from __future__ import annotations 4 | 5 | from typing import Union 6 | from typing_extensions import TypeAlias, TypedDict 7 | 8 | __all__ = ["RecipientReferenceParam", "ObjectReference"] 9 | 10 | 11 | class ObjectReference(TypedDict, total=False): 12 | id: str 13 | """An identifier for the recipient object.""" 14 | 15 | collection: str 16 | """The collection the recipient object belongs to.""" 17 | 18 | 19 | RecipientReferenceParam: TypeAlias = Union[str, ObjectReference] 20 | -------------------------------------------------------------------------------- /src/knockapi/types/providers/slack_check_auth_response.py: -------------------------------------------------------------------------------- 1 | # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | from typing import Optional 4 | 5 | from ..._models import BaseModel 6 | 7 | __all__ = ["SlackCheckAuthResponse", "Connection"] 8 | 9 | 10 | class Connection(BaseModel): 11 | ok: bool 12 | """Whether the Slack connection is valid.""" 13 | 14 | reason: Optional[str] = None 15 | """The reason for the Slack connection if it is not valid.""" 16 | 17 | 18 | class SlackCheckAuthResponse(BaseModel): 19 | connection: Connection 20 | """A Slack connection object.""" 21 | -------------------------------------------------------------------------------- /src/knockapi/types/providers/ms_team_list_teams_response.py: -------------------------------------------------------------------------------- 1 | # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | from typing import Optional 4 | 5 | from pydantic import Field as FieldInfo 6 | 7 | from ..._models import BaseModel 8 | 9 | __all__ = ["MsTeamListTeamsResponse"] 10 | 11 | 12 | class MsTeamListTeamsResponse(BaseModel): 13 | id: str 14 | """Microsoft Teams team ID.""" 15 | 16 | display_name: str = FieldInfo(alias="displayName") 17 | """Microsoft Teams team display name.""" 18 | 19 | description: Optional[str] = None 20 | """Microsoft Teams team description.""" 21 | -------------------------------------------------------------------------------- /src/knockapi/types/providers/ms_team_check_auth_response.py: -------------------------------------------------------------------------------- 1 | # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | from typing import Optional 4 | 5 | from ..._models import BaseModel 6 | 7 | __all__ = ["MsTeamCheckAuthResponse", "Connection"] 8 | 9 | 10 | class Connection(BaseModel): 11 | ok: bool 12 | """Whether the Microsoft Teams connection is valid.""" 13 | 14 | reason: Optional[str] = None 15 | """The reason for the Microsoft Teams connection if it is not valid.""" 16 | 17 | 18 | class MsTeamCheckAuthResponse(BaseModel): 19 | connection: Connection 20 | """A Microsoft Teams connection object.""" 21 | -------------------------------------------------------------------------------- /src/knockapi/types/messages/batch_mark_as_interacted_params.py: -------------------------------------------------------------------------------- 1 | # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | from __future__ import annotations 4 | 5 | from typing import Dict, Optional 6 | from typing_extensions import Required, TypedDict 7 | 8 | from ..._types import SequenceNotStr 9 | 10 | __all__ = ["BatchMarkAsInteractedParams"] 11 | 12 | 13 | class BatchMarkAsInteractedParams(TypedDict, total=False): 14 | message_ids: Required[SequenceNotStr[str]] 15 | """The message IDs to batch mark as interacted with.""" 16 | 17 | metadata: Optional[Dict[str, object]] 18 | """Metadata about the interaction.""" 19 | -------------------------------------------------------------------------------- /src/knockapi/types/message_list_activities_params.py: -------------------------------------------------------------------------------- 1 | # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | from __future__ import annotations 4 | 5 | from typing_extensions import TypedDict 6 | 7 | __all__ = ["MessageListActivitiesParams"] 8 | 9 | 10 | class MessageListActivitiesParams(TypedDict, total=False): 11 | after: str 12 | """The cursor to fetch entries after.""" 13 | 14 | before: str 15 | """The cursor to fetch entries before.""" 16 | 17 | page_size: int 18 | """The number of items per page (defaults to 50).""" 19 | 20 | trigger_data: str 21 | """The trigger data to filter activities by.""" 22 | -------------------------------------------------------------------------------- /src/knockapi/types/tenant_list_params.py: -------------------------------------------------------------------------------- 1 | # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | from __future__ import annotations 4 | 5 | from typing_extensions import TypedDict 6 | 7 | __all__ = ["TenantListParams"] 8 | 9 | 10 | class TenantListParams(TypedDict, total=False): 11 | after: str 12 | """The cursor to fetch entries after.""" 13 | 14 | before: str 15 | """The cursor to fetch entries before.""" 16 | 17 | name: str 18 | """Filter tenants by name.""" 19 | 20 | page_size: int 21 | """The number of items per page (defaults to 50).""" 22 | 23 | tenant_id: str 24 | """Filter tenants by ID.""" 25 | -------------------------------------------------------------------------------- /src/knockapi/types/providers/slack_list_channels_response.py: -------------------------------------------------------------------------------- 1 | # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | from ..._models import BaseModel 4 | 5 | __all__ = ["SlackListChannelsResponse"] 6 | 7 | 8 | class SlackListChannelsResponse(BaseModel): 9 | id: str 10 | """A Slack channel ID from the Slack provider.""" 11 | 12 | context_team_id: str 13 | """The team ID that the Slack channel belongs to.""" 14 | 15 | is_im: bool 16 | """Whether the Slack channel is an IM channel.""" 17 | 18 | is_private: bool 19 | """Whether the Slack channel is private.""" 20 | 21 | name: str 22 | """Slack channel name.""" 23 | -------------------------------------------------------------------------------- /src/knockapi/types/object_delete_subscriptions_params.py: -------------------------------------------------------------------------------- 1 | # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | from __future__ import annotations 4 | 5 | from typing_extensions import Required, TypedDict 6 | 7 | from .._types import SequenceNotStr 8 | from .recipient_reference_param import RecipientReferenceParam 9 | 10 | __all__ = ["ObjectDeleteSubscriptionsParams"] 11 | 12 | 13 | class ObjectDeleteSubscriptionsParams(TypedDict, total=False): 14 | recipients: Required[SequenceNotStr[RecipientReferenceParam]] 15 | """The recipients of the subscription. 16 | 17 | You can subscribe up to 100 recipients to an object at a time. 18 | """ 19 | -------------------------------------------------------------------------------- /src/knockapi/types/integrations/__init__.py: -------------------------------------------------------------------------------- 1 | # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | from __future__ import annotations 4 | 5 | from .census_custom_destination_params import CensusCustomDestinationParams as CensusCustomDestinationParams 6 | from .census_custom_destination_response import CensusCustomDestinationResponse as CensusCustomDestinationResponse 7 | from .hightouch_embedded_destination_params import ( 8 | HightouchEmbeddedDestinationParams as HightouchEmbeddedDestinationParams, 9 | ) 10 | from .hightouch_embedded_destination_response import ( 11 | HightouchEmbeddedDestinationResponse as HightouchEmbeddedDestinationResponse, 12 | ) 13 | -------------------------------------------------------------------------------- /src/knockapi/types/shared/page_info.py: -------------------------------------------------------------------------------- 1 | # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | from typing import Optional 4 | 5 | from pydantic import Field as FieldInfo 6 | 7 | from ..._models import BaseModel 8 | 9 | __all__ = ["PageInfo"] 10 | 11 | 12 | class PageInfo(BaseModel): 13 | api_typename: str = FieldInfo(alias="__typename") 14 | """The typename of the schema.""" 15 | 16 | page_size: int 17 | """The number of items per page (defaults to 50).""" 18 | 19 | after: Optional[str] = None 20 | """The cursor to fetch entries after.""" 21 | 22 | before: Optional[str] = None 23 | """The cursor to fetch entries before.""" 24 | -------------------------------------------------------------------------------- /src/knockapi/types/user_list_params.py: -------------------------------------------------------------------------------- 1 | # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | from __future__ import annotations 4 | 5 | from typing import List 6 | from typing_extensions import Literal, TypedDict 7 | 8 | __all__ = ["UserListParams"] 9 | 10 | 11 | class UserListParams(TypedDict, total=False): 12 | after: str 13 | """The cursor to fetch entries after.""" 14 | 15 | before: str 16 | """The cursor to fetch entries before.""" 17 | 18 | include: List[Literal["preferences"]] 19 | """Associated resources to include in the response.""" 20 | 21 | page_size: int 22 | """The number of items per page (defaults to 50).""" 23 | -------------------------------------------------------------------------------- /src/knockapi/types/users/bulk_set_preferences_params.py: -------------------------------------------------------------------------------- 1 | # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | from __future__ import annotations 4 | 5 | from typing_extensions import Required, TypedDict 6 | 7 | from ..._types import SequenceNotStr 8 | from ..recipients.preference_set_request_param import PreferenceSetRequestParam 9 | 10 | __all__ = ["BulkSetPreferencesParams"] 11 | 12 | 13 | class BulkSetPreferencesParams(TypedDict, total=False): 14 | preferences: Required[PreferenceSetRequestParam] 15 | """A request to set a preference set for a recipient.""" 16 | 17 | user_ids: Required[SequenceNotStr[str]] 18 | """A list of user IDs.""" 19 | -------------------------------------------------------------------------------- /scripts/bootstrap: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | 5 | cd "$(dirname "$0")/.." 6 | 7 | if [ -f "Brewfile" ] && [ "$(uname -s)" = "Darwin" ] && [ "$SKIP_BREW" != "1" ] && [ -t 0 ]; then 8 | brew bundle check >/dev/null 2>&1 || { 9 | echo -n "==> Install Homebrew dependencies? (y/N): " 10 | read -r response 11 | case "$response" in 12 | [yY][eE][sS]|[yY]) 13 | brew bundle 14 | ;; 15 | *) 16 | ;; 17 | esac 18 | echo 19 | } 20 | fi 21 | 22 | echo "==> Installing Python dependencies…" 23 | 24 | # experimental uv support makes installations significantly faster 25 | rye config --set-bool behavior.use-uv=true 26 | 27 | rye sync --all-features 28 | -------------------------------------------------------------------------------- /src/knockapi/types/object_list_params.py: -------------------------------------------------------------------------------- 1 | # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | from __future__ import annotations 4 | 5 | from typing import List 6 | from typing_extensions import Literal, TypedDict 7 | 8 | __all__ = ["ObjectListParams"] 9 | 10 | 11 | class ObjectListParams(TypedDict, total=False): 12 | after: str 13 | """The cursor to fetch entries after.""" 14 | 15 | before: str 16 | """The cursor to fetch entries before.""" 17 | 18 | include: List[Literal["preferences"]] 19 | """Includes preferences of the objects in the response.""" 20 | 21 | page_size: int 22 | """The number of items per page (defaults to 50).""" 23 | -------------------------------------------------------------------------------- /.github/workflows/release-doctor.yml: -------------------------------------------------------------------------------- 1 | name: Release Doctor 2 | on: 3 | pull_request: 4 | branches: 5 | - main 6 | workflow_dispatch: 7 | 8 | jobs: 9 | release_doctor: 10 | name: release doctor 11 | runs-on: ubuntu-latest 12 | if: github.repository == 'knocklabs/knock-python' && (github.event_name == 'push' || github.event_name == 'workflow_dispatch' || startsWith(github.head_ref, 'release-please') || github.head_ref == 'next') 13 | 14 | steps: 15 | - uses: actions/checkout@v4 16 | 17 | - name: Check release environment 18 | run: | 19 | bash ./bin/check-release-environment 20 | env: 21 | PYPI_TOKEN: ${{ secrets.KNOCK_PYPI_TOKEN || secrets.PYPI_TOKEN }} 22 | -------------------------------------------------------------------------------- /src/knockapi/types/integrations/census_custom_destination_params.py: -------------------------------------------------------------------------------- 1 | # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | from __future__ import annotations 4 | 5 | from typing import Dict 6 | from typing_extensions import Required, TypedDict 7 | 8 | __all__ = ["CensusCustomDestinationParams"] 9 | 10 | 11 | class CensusCustomDestinationParams(TypedDict, total=False): 12 | id: Required[str] 13 | """The unique identifier for the RPC request.""" 14 | 15 | jsonrpc: Required[str] 16 | """The JSON-RPC version.""" 17 | 18 | method: Required[str] 19 | """The method name to execute.""" 20 | 21 | params: Dict[str, object] 22 | """The parameters for the method.""" 23 | -------------------------------------------------------------------------------- /src/knockapi/types/object_list_schedules_params.py: -------------------------------------------------------------------------------- 1 | # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | from __future__ import annotations 4 | 5 | from typing_extensions import TypedDict 6 | 7 | __all__ = ["ObjectListSchedulesParams"] 8 | 9 | 10 | class ObjectListSchedulesParams(TypedDict, total=False): 11 | after: str 12 | """The cursor to fetch entries after.""" 13 | 14 | before: str 15 | """The cursor to fetch entries before.""" 16 | 17 | page_size: int 18 | """The number of items per page (defaults to 50).""" 19 | 20 | tenant: str 21 | """Filter schedules by tenant id.""" 22 | 23 | workflow: str 24 | """Filter schedules by workflow id.""" 25 | -------------------------------------------------------------------------------- /src/knockapi/_utils/_resources_proxy.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | from typing import Any 4 | from typing_extensions import override 5 | 6 | from ._proxy import LazyProxy 7 | 8 | 9 | class ResourcesProxy(LazyProxy[Any]): 10 | """A proxy for the `knockapi.resources` module. 11 | 12 | This is used so that we can lazily import `knockapi.resources` only when 13 | needed *and* so that users can just import `knockapi` and reference `knockapi.resources` 14 | """ 15 | 16 | @override 17 | def __load__(self) -> Any: 18 | import importlib 19 | 20 | mod = importlib.import_module("knockapi.resources") 21 | return mod 22 | 23 | 24 | resources = ResourcesProxy().__as_proxied__() 25 | -------------------------------------------------------------------------------- /src/knockapi/types/recipients/aws_sns_push_channel_data_target_arns_only_param.py: -------------------------------------------------------------------------------- 1 | # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | from __future__ import annotations 4 | 5 | from typing_extensions import Required, TypedDict 6 | 7 | from ..._types import SequenceNotStr 8 | 9 | __all__ = ["AwsSnsPushChannelDataTargetArnsOnlyParam"] 10 | 11 | 12 | class AwsSnsPushChannelDataTargetArnsOnlyParam(TypedDict, total=False): 13 | target_arns: Required[SequenceNotStr[str]] 14 | """A list of platform endpoint ARNs. 15 | 16 | See 17 | [Setting up an Amazon SNS platform endpoint for mobile notifications](https://docs.aws.amazon.com/sns/latest/dg/mobile-platform-endpoint.html). 18 | """ 19 | -------------------------------------------------------------------------------- /src/knockapi/types/user_list_schedules_params.py: -------------------------------------------------------------------------------- 1 | # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | from __future__ import annotations 4 | 5 | from typing_extensions import TypedDict 6 | 7 | __all__ = ["UserListSchedulesParams"] 8 | 9 | 10 | class UserListSchedulesParams(TypedDict, total=False): 11 | after: str 12 | """The cursor to fetch entries after.""" 13 | 14 | before: str 15 | """The cursor to fetch entries before.""" 16 | 17 | page_size: int 18 | """The number of items per page (defaults to 50).""" 19 | 20 | tenant: str 21 | """The tenant ID to filter schedules for.""" 22 | 23 | workflow: str 24 | """The workflow key to filter schedules for.""" 25 | -------------------------------------------------------------------------------- /src/knockapi/types/integrations/hightouch_embedded_destination_params.py: -------------------------------------------------------------------------------- 1 | # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | from __future__ import annotations 4 | 5 | from typing import Dict 6 | from typing_extensions import Required, TypedDict 7 | 8 | __all__ = ["HightouchEmbeddedDestinationParams"] 9 | 10 | 11 | class HightouchEmbeddedDestinationParams(TypedDict, total=False): 12 | id: Required[str] 13 | """The unique identifier for the RPC request.""" 14 | 15 | jsonrpc: Required[str] 16 | """The JSON-RPC version.""" 17 | 18 | method: Required[str] 19 | """The method name to execute.""" 20 | 21 | params: Dict[str, object] 22 | """The parameters for the method.""" 23 | -------------------------------------------------------------------------------- /src/knockapi/types/object_add_subscriptions_params.py: -------------------------------------------------------------------------------- 1 | # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | from __future__ import annotations 4 | 5 | from typing import Dict, Optional 6 | from typing_extensions import Required, TypedDict 7 | 8 | from .._types import SequenceNotStr 9 | from .recipient_request_param import RecipientRequestParam 10 | 11 | __all__ = ["ObjectAddSubscriptionsParams"] 12 | 13 | 14 | class ObjectAddSubscriptionsParams(TypedDict, total=False): 15 | recipients: Required[SequenceNotStr[RecipientRequestParam]] 16 | """The recipients of the subscription. 17 | 18 | You can subscribe up to 100 recipients to an object at a time. 19 | """ 20 | 21 | properties: Optional[Dict[str, object]] 22 | """The custom properties associated with the subscription relationship.""" 23 | -------------------------------------------------------------------------------- /src/knockapi/types/audience_remove_members_params.py: -------------------------------------------------------------------------------- 1 | # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | from __future__ import annotations 4 | 5 | from typing import Iterable, Optional 6 | from typing_extensions import Required, TypedDict 7 | 8 | __all__ = ["AudienceRemoveMembersParams", "Member", "MemberUser"] 9 | 10 | 11 | class AudienceRemoveMembersParams(TypedDict, total=False): 12 | members: Required[Iterable[Member]] 13 | """A list of audience members to remove.""" 14 | 15 | 16 | class MemberUser(TypedDict, total=False): 17 | id: str 18 | """The unique identifier of the user.""" 19 | 20 | 21 | class Member(TypedDict, total=False): 22 | user: Required[MemberUser] 23 | """An object containing the user's ID.""" 24 | 25 | tenant: Optional[str] 26 | """The unique identifier for the tenant.""" 27 | -------------------------------------------------------------------------------- /src/knockapi/_utils/_logs.py: -------------------------------------------------------------------------------- 1 | import os 2 | import logging 3 | 4 | logger: logging.Logger = logging.getLogger("knockapi") 5 | httpx_logger: logging.Logger = logging.getLogger("httpx") 6 | 7 | 8 | def _basic_config() -> None: 9 | # e.g. [2023-10-05 14:12:26 - knockapi._base_client:818 - DEBUG] HTTP Request: POST http://127.0.0.1:4010/foo/bar "200 OK" 10 | logging.basicConfig( 11 | format="[%(asctime)s - %(name)s:%(lineno)d - %(levelname)s] %(message)s", 12 | datefmt="%Y-%m-%d %H:%M:%S", 13 | ) 14 | 15 | 16 | def setup_logging() -> None: 17 | env = os.environ.get("KNOCK_LOG") 18 | if env == "debug": 19 | _basic_config() 20 | logger.setLevel(logging.DEBUG) 21 | httpx_logger.setLevel(logging.DEBUG) 22 | elif env == "info": 23 | _basic_config() 24 | logger.setLevel(logging.INFO) 25 | httpx_logger.setLevel(logging.INFO) 26 | -------------------------------------------------------------------------------- /src/knockapi/types/audience_add_members_params.py: -------------------------------------------------------------------------------- 1 | # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | from __future__ import annotations 4 | 5 | from typing import Iterable, Optional 6 | from typing_extensions import Required, TypedDict 7 | 8 | __all__ = ["AudienceAddMembersParams", "Member", "MemberUser"] 9 | 10 | 11 | class AudienceAddMembersParams(TypedDict, total=False): 12 | members: Required[Iterable[Member]] 13 | """A list of audience members to add. Limited to 1,000 members per request.""" 14 | 15 | 16 | class MemberUser(TypedDict, total=False): 17 | id: str 18 | """The unique identifier of the user.""" 19 | 20 | 21 | class Member(TypedDict, total=False): 22 | user: Required[MemberUser] 23 | """An object containing the user's ID.""" 24 | 25 | tenant: Optional[str] 26 | """The unique identifier for the tenant.""" 27 | -------------------------------------------------------------------------------- /scripts/utils/upload-artifact.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -exuo pipefail 3 | 4 | FILENAME=$(basename dist/*.whl) 5 | 6 | RESPONSE=$(curl -X POST "$URL?filename=$FILENAME" \ 7 | -H "Authorization: Bearer $AUTH" \ 8 | -H "Content-Type: application/json") 9 | 10 | SIGNED_URL=$(echo "$RESPONSE" | jq -r '.url') 11 | 12 | if [[ "$SIGNED_URL" == "null" ]]; then 13 | echo -e "\033[31mFailed to get signed URL.\033[0m" 14 | exit 1 15 | fi 16 | 17 | UPLOAD_RESPONSE=$(curl -v -X PUT \ 18 | -H "Content-Type: binary/octet-stream" \ 19 | --data-binary "@dist/$FILENAME" "$SIGNED_URL" 2>&1) 20 | 21 | if echo "$UPLOAD_RESPONSE" | grep -q "HTTP/[0-9.]* 200"; then 22 | echo -e "\033[32mUploaded build to Stainless storage.\033[0m" 23 | echo -e "\033[32mInstallation: pip install 'https://pkg.stainless.com/s/knock-python/$SHA/$FILENAME'\033[0m" 24 | else 25 | echo -e "\033[31mFailed to upload artifact.\033[0m" 26 | exit 1 27 | fi 28 | -------------------------------------------------------------------------------- /src/knockapi/types/schedule_list_params.py: -------------------------------------------------------------------------------- 1 | # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | from __future__ import annotations 4 | 5 | from typing_extensions import Required, TypedDict 6 | 7 | from .._types import SequenceNotStr 8 | from .recipient_reference_param import RecipientReferenceParam 9 | 10 | __all__ = ["ScheduleListParams"] 11 | 12 | 13 | class ScheduleListParams(TypedDict, total=False): 14 | workflow: Required[str] 15 | """Filter by workflow key.""" 16 | 17 | after: str 18 | """The cursor to fetch entries after.""" 19 | 20 | before: str 21 | """The cursor to fetch entries before.""" 22 | 23 | page_size: int 24 | """The number of items per page (defaults to 50).""" 25 | 26 | recipients: SequenceNotStr[RecipientReferenceParam] 27 | """Filter by recipient references.""" 28 | 29 | tenant: str 30 | """Filter by tenant ID.""" 31 | -------------------------------------------------------------------------------- /src/knockapi/types/object.py: -------------------------------------------------------------------------------- 1 | # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | from typing import Dict, Optional 4 | from datetime import datetime 5 | 6 | from pydantic import Field as FieldInfo 7 | 8 | from .._models import BaseModel 9 | 10 | __all__ = ["Object"] 11 | 12 | 13 | class Object(BaseModel): 14 | id: str 15 | """Unique identifier for the object.""" 16 | 17 | api_typename: str = FieldInfo(alias="__typename") 18 | """The typename of the schema.""" 19 | 20 | collection: str 21 | """The collection this object belongs to.""" 22 | 23 | updated_at: datetime 24 | """The timestamp when the resource was last updated.""" 25 | 26 | created_at: Optional[datetime] = None 27 | """Timestamp when the resource was created.""" 28 | 29 | properties: Optional[Dict[str, object]] = None 30 | """The custom properties associated with the object.""" 31 | -------------------------------------------------------------------------------- /src/knockapi/types/objects/bulk_delete_subscriptions_params.py: -------------------------------------------------------------------------------- 1 | # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | from __future__ import annotations 4 | 5 | from typing import Iterable 6 | from typing_extensions import Required, TypedDict 7 | 8 | from ..._types import SequenceNotStr 9 | from ..recipient_reference_param import RecipientReferenceParam 10 | 11 | __all__ = ["BulkDeleteSubscriptionsParams", "Subscription"] 12 | 13 | 14 | class BulkDeleteSubscriptionsParams(TypedDict, total=False): 15 | subscriptions: Required[Iterable[Subscription]] 16 | """A nested list of subscriptions.""" 17 | 18 | 19 | class Subscription(TypedDict, total=False): 20 | id: Required[str] 21 | """Unique identifier for the object.""" 22 | 23 | recipients: Required[SequenceNotStr[RecipientReferenceParam]] 24 | """The recipients of the subscription. 25 | 26 | You can subscribe up to 100 recipients to an object at a time. 27 | """ 28 | -------------------------------------------------------------------------------- /src/knockapi/types/user_list_subscriptions_params.py: -------------------------------------------------------------------------------- 1 | # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | from __future__ import annotations 4 | 5 | from typing import List 6 | from typing_extensions import Literal, TypedDict 7 | 8 | from .._types import SequenceNotStr 9 | from .recipient_reference_param import RecipientReferenceParam 10 | 11 | __all__ = ["UserListSubscriptionsParams"] 12 | 13 | 14 | class UserListSubscriptionsParams(TypedDict, total=False): 15 | after: str 16 | """The cursor to fetch entries after.""" 17 | 18 | before: str 19 | """The cursor to fetch entries before.""" 20 | 21 | include: List[Literal["preferences"]] 22 | """Associated resources to include in the response.""" 23 | 24 | objects: SequenceNotStr[RecipientReferenceParam] 25 | """Only returns subscriptions for the specified object references.""" 26 | 27 | page_size: int 28 | """The number of items per page (defaults to 50).""" 29 | -------------------------------------------------------------------------------- /.github/workflows/publish-pypi.yml: -------------------------------------------------------------------------------- 1 | # This workflow is triggered when a GitHub release is created. 2 | # It can also be run manually to re-publish to PyPI in case it failed for some reason. 3 | # You can run this workflow by navigating to https://www.github.com/knocklabs/knock-python/actions/workflows/publish-pypi.yml 4 | name: Publish PyPI 5 | on: 6 | workflow_dispatch: 7 | 8 | release: 9 | types: [published] 10 | 11 | jobs: 12 | publish: 13 | name: publish 14 | runs-on: ubuntu-latest 15 | 16 | steps: 17 | - uses: actions/checkout@v4 18 | 19 | - name: Install Rye 20 | run: | 21 | curl -sSf https://rye.astral.sh/get | bash 22 | echo "$HOME/.rye/shims" >> $GITHUB_PATH 23 | env: 24 | RYE_VERSION: '0.44.0' 25 | RYE_INSTALL_OPTION: '--yes' 26 | 27 | - name: Publish to PyPI 28 | run: | 29 | bash ./bin/publish-pypi 30 | env: 31 | PYPI_TOKEN: ${{ secrets.KNOCK_PYPI_TOKEN || secrets.PYPI_TOKEN }} 32 | -------------------------------------------------------------------------------- /src/knockapi/types/audience_member.py: -------------------------------------------------------------------------------- 1 | # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | from typing import Optional 4 | from datetime import datetime 5 | 6 | from pydantic import Field as FieldInfo 7 | 8 | from .user import User 9 | from .._models import BaseModel 10 | 11 | __all__ = ["AudienceMember"] 12 | 13 | 14 | class AudienceMember(BaseModel): 15 | api_typename: str = FieldInfo(alias="__typename") 16 | """The typename of the schema.""" 17 | 18 | added_at: datetime 19 | """Timestamp when the resource was created.""" 20 | 21 | user: User 22 | """ 23 | A [User](/concepts/users) represents an individual in your system who can 24 | receive notifications through Knock. Users are the most common recipients of 25 | notifications and are always referenced by your internal identifier. 26 | """ 27 | 28 | user_id: str 29 | """The unique identifier of the user.""" 30 | 31 | tenant: Optional[str] = None 32 | """The unique identifier for the tenant.""" 33 | -------------------------------------------------------------------------------- /scripts/mock: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | 5 | cd "$(dirname "$0")/.." 6 | 7 | if [[ -n "$1" && "$1" != '--'* ]]; then 8 | URL="$1" 9 | shift 10 | else 11 | URL="$(grep 'openapi_spec_url' .stats.yml | cut -d' ' -f2)" 12 | fi 13 | 14 | # Check if the URL is empty 15 | if [ -z "$URL" ]; then 16 | echo "Error: No OpenAPI spec path/url provided or found in .stats.yml" 17 | exit 1 18 | fi 19 | 20 | echo "==> Starting mock server with URL ${URL}" 21 | 22 | # Run prism mock on the given spec 23 | if [ "$1" == "--daemon" ]; then 24 | npm exec --package=@stainless-api/prism-cli@5.15.0 -- prism mock "$URL" &> .prism.log & 25 | 26 | # Wait for server to come online 27 | echo -n "Waiting for server" 28 | while ! grep -q "✖ fatal\|Prism is listening" ".prism.log" ; do 29 | echo -n "." 30 | sleep 0.1 31 | done 32 | 33 | if grep -q "✖ fatal" ".prism.log"; then 34 | cat .prism.log 35 | exit 1 36 | fi 37 | 38 | echo 39 | else 40 | npm exec --package=@stainless-api/prism-cli@5.15.0 -- prism mock "$URL" 41 | fi 42 | -------------------------------------------------------------------------------- /src/knockapi/types/objects/bulk_add_subscriptions_params.py: -------------------------------------------------------------------------------- 1 | # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | from __future__ import annotations 4 | 5 | from typing import Dict, Iterable, Optional 6 | from typing_extensions import Required, TypedDict 7 | 8 | from ..._types import SequenceNotStr 9 | from ..recipient_request_param import RecipientRequestParam 10 | 11 | __all__ = ["BulkAddSubscriptionsParams", "Subscription"] 12 | 13 | 14 | class BulkAddSubscriptionsParams(TypedDict, total=False): 15 | subscriptions: Required[Iterable[Subscription]] 16 | """A nested list of subscriptions.""" 17 | 18 | 19 | class Subscription(TypedDict, total=False): 20 | id: Required[str] 21 | """Unique identifier for the object.""" 22 | 23 | recipients: Required[SequenceNotStr[RecipientRequestParam]] 24 | """The recipients of the subscription. 25 | 26 | You can subscribe up to 100 recipients to an object at a time. 27 | """ 28 | 29 | properties: Optional[Dict[str, object]] 30 | """The custom properties associated with the subscription relationship.""" 31 | -------------------------------------------------------------------------------- /src/knockapi/types/users/guide_mark_message_as_seen_params.py: -------------------------------------------------------------------------------- 1 | # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | from __future__ import annotations 4 | 5 | from typing import Dict, Optional 6 | from typing_extensions import Required, TypedDict 7 | 8 | __all__ = ["GuideMarkMessageAsSeenParams"] 9 | 10 | 11 | class GuideMarkMessageAsSeenParams(TypedDict, total=False): 12 | channel_id: Required[str] 13 | """The unique identifier for the channel.""" 14 | 15 | guide_id: Required[str] 16 | """The unique identifier for the guide.""" 17 | 18 | guide_key: Required[str] 19 | """The key of the guide.""" 20 | 21 | guide_step_ref: Required[str] 22 | """The step reference of the guide.""" 23 | 24 | content: Dict[str, object] 25 | """The content of the guide.""" 26 | 27 | data: Dict[str, object] 28 | """The data of the guide.""" 29 | 30 | is_final: bool 31 | """Whether the guide is final.""" 32 | 33 | metadata: Dict[str, object] 34 | """The metadata of the guide.""" 35 | 36 | tenant: Optional[str] 37 | """The tenant ID of the guide.""" 38 | -------------------------------------------------------------------------------- /src/knockapi/types/recipients/subscription.py: -------------------------------------------------------------------------------- 1 | # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | import builtins 4 | from typing import Dict, Optional 5 | from datetime import datetime 6 | 7 | from pydantic import Field as FieldInfo 8 | 9 | from ..object import Object 10 | from ..._models import BaseModel 11 | from ..recipient import Recipient 12 | 13 | __all__ = ["Subscription"] 14 | 15 | 16 | class Subscription(BaseModel): 17 | api_typename: str = FieldInfo(alias="__typename") 18 | """The typename of the schema.""" 19 | 20 | inserted_at: datetime 21 | """Timestamp when the resource was created.""" 22 | 23 | object: Object 24 | """A custom [Object](/concepts/objects) entity which belongs to a collection.""" 25 | 26 | recipient: Recipient 27 | """A recipient of a notification, which is either a user or an object.""" 28 | 29 | updated_at: datetime 30 | """The timestamp when the resource was last updated.""" 31 | 32 | properties: Optional[Dict[str, builtins.object]] = None 33 | """The custom properties associated with the subscription relationship.""" 34 | -------------------------------------------------------------------------------- /src/knockapi/types/users/guide_mark_message_as_archived_params.py: -------------------------------------------------------------------------------- 1 | # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | from __future__ import annotations 4 | 5 | from typing import Dict, Optional 6 | from typing_extensions import Required, TypedDict 7 | 8 | __all__ = ["GuideMarkMessageAsArchivedParams"] 9 | 10 | 11 | class GuideMarkMessageAsArchivedParams(TypedDict, total=False): 12 | channel_id: Required[str] 13 | """The unique identifier for the channel.""" 14 | 15 | guide_id: Required[str] 16 | """The unique identifier for the guide.""" 17 | 18 | guide_key: Required[str] 19 | """The key of the guide.""" 20 | 21 | guide_step_ref: Required[str] 22 | """The step reference of the guide.""" 23 | 24 | content: Dict[str, object] 25 | """The content of the guide.""" 26 | 27 | data: Dict[str, object] 28 | """The data of the guide.""" 29 | 30 | is_final: bool 31 | """Whether the guide is final.""" 32 | 33 | metadata: Dict[str, object] 34 | """The metadata of the guide.""" 35 | 36 | tenant: Optional[str] 37 | """The tenant ID of the guide.""" 38 | -------------------------------------------------------------------------------- /src/knockapi/resources/objects/__init__.py: -------------------------------------------------------------------------------- 1 | # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | from .bulk import ( 4 | BulkResource, 5 | AsyncBulkResource, 6 | BulkResourceWithRawResponse, 7 | AsyncBulkResourceWithRawResponse, 8 | BulkResourceWithStreamingResponse, 9 | AsyncBulkResourceWithStreamingResponse, 10 | ) 11 | from .objects import ( 12 | ObjectsResource, 13 | AsyncObjectsResource, 14 | ObjectsResourceWithRawResponse, 15 | AsyncObjectsResourceWithRawResponse, 16 | ObjectsResourceWithStreamingResponse, 17 | AsyncObjectsResourceWithStreamingResponse, 18 | ) 19 | 20 | __all__ = [ 21 | "BulkResource", 22 | "AsyncBulkResource", 23 | "BulkResourceWithRawResponse", 24 | "AsyncBulkResourceWithRawResponse", 25 | "BulkResourceWithStreamingResponse", 26 | "AsyncBulkResourceWithStreamingResponse", 27 | "ObjectsResource", 28 | "AsyncObjectsResource", 29 | "ObjectsResourceWithRawResponse", 30 | "AsyncObjectsResourceWithRawResponse", 31 | "ObjectsResourceWithStreamingResponse", 32 | "AsyncObjectsResourceWithStreamingResponse", 33 | ] 34 | -------------------------------------------------------------------------------- /src/knockapi/resources/tenants/__init__.py: -------------------------------------------------------------------------------- 1 | # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | from .bulk import ( 4 | BulkResource, 5 | AsyncBulkResource, 6 | BulkResourceWithRawResponse, 7 | AsyncBulkResourceWithRawResponse, 8 | BulkResourceWithStreamingResponse, 9 | AsyncBulkResourceWithStreamingResponse, 10 | ) 11 | from .tenants import ( 12 | TenantsResource, 13 | AsyncTenantsResource, 14 | TenantsResourceWithRawResponse, 15 | AsyncTenantsResourceWithRawResponse, 16 | TenantsResourceWithStreamingResponse, 17 | AsyncTenantsResourceWithStreamingResponse, 18 | ) 19 | 20 | __all__ = [ 21 | "BulkResource", 22 | "AsyncBulkResource", 23 | "BulkResourceWithRawResponse", 24 | "AsyncBulkResourceWithRawResponse", 25 | "BulkResourceWithStreamingResponse", 26 | "AsyncBulkResourceWithStreamingResponse", 27 | "TenantsResource", 28 | "AsyncTenantsResource", 29 | "TenantsResourceWithRawResponse", 30 | "AsyncTenantsResourceWithRawResponse", 31 | "TenantsResourceWithStreamingResponse", 32 | "AsyncTenantsResourceWithStreamingResponse", 33 | ] 34 | -------------------------------------------------------------------------------- /src/knockapi/types/users/guide_mark_message_as_interacted_params.py: -------------------------------------------------------------------------------- 1 | # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | from __future__ import annotations 4 | 5 | from typing import Dict, Optional 6 | from typing_extensions import Required, TypedDict 7 | 8 | __all__ = ["GuideMarkMessageAsInteractedParams"] 9 | 10 | 11 | class GuideMarkMessageAsInteractedParams(TypedDict, total=False): 12 | channel_id: Required[str] 13 | """The unique identifier for the channel.""" 14 | 15 | guide_id: Required[str] 16 | """The unique identifier for the guide.""" 17 | 18 | guide_key: Required[str] 19 | """The key of the guide.""" 20 | 21 | guide_step_ref: Required[str] 22 | """The step reference of the guide.""" 23 | 24 | content: Dict[str, object] 25 | """The content of the guide.""" 26 | 27 | data: Dict[str, object] 28 | """The data of the guide.""" 29 | 30 | is_final: bool 31 | """Whether the guide is final.""" 32 | 33 | metadata: Dict[str, object] 34 | """The metadata of the guide.""" 35 | 36 | tenant: Optional[str] 37 | """The tenant ID of the guide.""" 38 | -------------------------------------------------------------------------------- /src/knockapi/types/workflow_cancel_params.py: -------------------------------------------------------------------------------- 1 | # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | from __future__ import annotations 4 | 5 | from typing import Optional 6 | from typing_extensions import Required, TypedDict 7 | 8 | from .._types import SequenceNotStr 9 | from .recipient_reference_param import RecipientReferenceParam 10 | 11 | __all__ = ["WorkflowCancelParams"] 12 | 13 | 14 | class WorkflowCancelParams(TypedDict, total=False): 15 | cancellation_key: Required[str] 16 | """ 17 | An optional key that is used to reference a specific workflow trigger request 18 | when issuing a [workflow cancellation](/send-notifications/canceling-workflows) 19 | request. Must be provided while triggering a workflow in order to enable 20 | subsequent cancellation. Should be unique across trigger requests to avoid 21 | unintentional cancellations. 22 | """ 23 | 24 | recipients: Optional[SequenceNotStr[RecipientReferenceParam]] 25 | """A list of recipients to cancel the notification for. 26 | 27 | If omitted, cancels for all recipients associated with the cancellation key. 28 | """ 29 | -------------------------------------------------------------------------------- /tests/test_utils/test_proxy.py: -------------------------------------------------------------------------------- 1 | import operator 2 | from typing import Any 3 | from typing_extensions import override 4 | 5 | from knockapi._utils import LazyProxy 6 | 7 | 8 | class RecursiveLazyProxy(LazyProxy[Any]): 9 | @override 10 | def __load__(self) -> Any: 11 | return self 12 | 13 | def __call__(self, *_args: Any, **_kwds: Any) -> Any: 14 | raise RuntimeError("This should never be called!") 15 | 16 | 17 | def test_recursive_proxy() -> None: 18 | proxy = RecursiveLazyProxy() 19 | assert repr(proxy) == "RecursiveLazyProxy" 20 | assert str(proxy) == "RecursiveLazyProxy" 21 | assert dir(proxy) == [] 22 | assert type(proxy).__name__ == "RecursiveLazyProxy" 23 | assert type(operator.attrgetter("name.foo.bar.baz")(proxy)).__name__ == "RecursiveLazyProxy" 24 | 25 | 26 | def test_isinstance_does_not_error() -> None: 27 | class AlwaysErrorProxy(LazyProxy[Any]): 28 | @override 29 | def __load__(self) -> Any: 30 | raise RuntimeError("Mocking missing dependency") 31 | 32 | proxy = AlwaysErrorProxy() 33 | assert not isinstance(proxy, dict) 34 | assert isinstance(proxy, LazyProxy) 35 | -------------------------------------------------------------------------------- /src/knockapi/resources/channels/__init__.py: -------------------------------------------------------------------------------- 1 | # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | from .bulk import ( 4 | BulkResource, 5 | AsyncBulkResource, 6 | BulkResourceWithRawResponse, 7 | AsyncBulkResourceWithRawResponse, 8 | BulkResourceWithStreamingResponse, 9 | AsyncBulkResourceWithStreamingResponse, 10 | ) 11 | from .channels import ( 12 | ChannelsResource, 13 | AsyncChannelsResource, 14 | ChannelsResourceWithRawResponse, 15 | AsyncChannelsResourceWithRawResponse, 16 | ChannelsResourceWithStreamingResponse, 17 | AsyncChannelsResourceWithStreamingResponse, 18 | ) 19 | 20 | __all__ = [ 21 | "BulkResource", 22 | "AsyncBulkResource", 23 | "BulkResourceWithRawResponse", 24 | "AsyncBulkResourceWithRawResponse", 25 | "BulkResourceWithStreamingResponse", 26 | "AsyncBulkResourceWithStreamingResponse", 27 | "ChannelsResource", 28 | "AsyncChannelsResource", 29 | "ChannelsResourceWithRawResponse", 30 | "AsyncChannelsResourceWithRawResponse", 31 | "ChannelsResourceWithStreamingResponse", 32 | "AsyncChannelsResourceWithStreamingResponse", 33 | ] 34 | -------------------------------------------------------------------------------- /src/knockapi/types/shared/condition.py: -------------------------------------------------------------------------------- 1 | # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | from typing import Optional 4 | from typing_extensions import Literal 5 | 6 | from ..._models import BaseModel 7 | 8 | __all__ = ["Condition"] 9 | 10 | 11 | class Condition(BaseModel): 12 | argument: Optional[str] = None 13 | """The argument value to compare against in the condition.""" 14 | 15 | operator: Literal[ 16 | "equal_to", 17 | "not_equal_to", 18 | "greater_than", 19 | "less_than", 20 | "greater_than_or_equal_to", 21 | "less_than_or_equal_to", 22 | "contains", 23 | "not_contains", 24 | "empty", 25 | "not_empty", 26 | "contains_all", 27 | "is_timestamp", 28 | "is_not_timestamp", 29 | "is_timestamp_after", 30 | "is_timestamp_before", 31 | "is_timestamp_between", 32 | "is_audience_member", 33 | "is_not_audience_member", 34 | ] 35 | """The operator to use in the condition evaluation.""" 36 | 37 | variable: str 38 | """The variable to be evaluated in the condition.""" 39 | -------------------------------------------------------------------------------- /src/knockapi/resources/messages/__init__.py: -------------------------------------------------------------------------------- 1 | # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | from .batch import ( 4 | BatchResource, 5 | AsyncBatchResource, 6 | BatchResourceWithRawResponse, 7 | AsyncBatchResourceWithRawResponse, 8 | BatchResourceWithStreamingResponse, 9 | AsyncBatchResourceWithStreamingResponse, 10 | ) 11 | from .messages import ( 12 | MessagesResource, 13 | AsyncMessagesResource, 14 | MessagesResourceWithRawResponse, 15 | AsyncMessagesResourceWithRawResponse, 16 | MessagesResourceWithStreamingResponse, 17 | AsyncMessagesResourceWithStreamingResponse, 18 | ) 19 | 20 | __all__ = [ 21 | "BatchResource", 22 | "AsyncBatchResource", 23 | "BatchResourceWithRawResponse", 24 | "AsyncBatchResourceWithRawResponse", 25 | "BatchResourceWithStreamingResponse", 26 | "AsyncBatchResourceWithStreamingResponse", 27 | "MessagesResource", 28 | "AsyncMessagesResource", 29 | "MessagesResourceWithRawResponse", 30 | "AsyncMessagesResourceWithRawResponse", 31 | "MessagesResourceWithStreamingResponse", 32 | "AsyncMessagesResourceWithStreamingResponse", 33 | ] 34 | -------------------------------------------------------------------------------- /src/knockapi/resources/schedules/__init__.py: -------------------------------------------------------------------------------- 1 | # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | from .bulk import ( 4 | BulkResource, 5 | AsyncBulkResource, 6 | BulkResourceWithRawResponse, 7 | AsyncBulkResourceWithRawResponse, 8 | BulkResourceWithStreamingResponse, 9 | AsyncBulkResourceWithStreamingResponse, 10 | ) 11 | from .schedules import ( 12 | SchedulesResource, 13 | AsyncSchedulesResource, 14 | SchedulesResourceWithRawResponse, 15 | AsyncSchedulesResourceWithRawResponse, 16 | SchedulesResourceWithStreamingResponse, 17 | AsyncSchedulesResourceWithStreamingResponse, 18 | ) 19 | 20 | __all__ = [ 21 | "BulkResource", 22 | "AsyncBulkResource", 23 | "BulkResourceWithRawResponse", 24 | "AsyncBulkResourceWithRawResponse", 25 | "BulkResourceWithStreamingResponse", 26 | "AsyncBulkResourceWithStreamingResponse", 27 | "SchedulesResource", 28 | "AsyncSchedulesResource", 29 | "SchedulesResourceWithRawResponse", 30 | "AsyncSchedulesResourceWithRawResponse", 31 | "SchedulesResourceWithStreamingResponse", 32 | "AsyncSchedulesResourceWithStreamingResponse", 33 | ] 34 | -------------------------------------------------------------------------------- /src/knockapi/types/schedule_repeat_rule.py: -------------------------------------------------------------------------------- 1 | # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | from typing import List, Optional 4 | from typing_extensions import Literal 5 | 6 | from pydantic import Field as FieldInfo 7 | 8 | from .._models import BaseModel 9 | 10 | __all__ = ["ScheduleRepeatRule"] 11 | 12 | 13 | class ScheduleRepeatRule(BaseModel): 14 | frequency: Literal["daily", "weekly", "monthly", "hourly"] 15 | """The frequency of the schedule.""" 16 | 17 | api_typename: Optional[str] = FieldInfo(alias="__typename", default=None) 18 | """The typename of the schema.""" 19 | 20 | day_of_month: Optional[int] = None 21 | """The day of the month to repeat the schedule.""" 22 | 23 | days: Optional[List[Literal["mon", "tue", "wed", "thu", "fri", "sat", "sun"]]] = None 24 | """The days of the week to repeat the schedule.""" 25 | 26 | hours: Optional[int] = None 27 | """The hour of the day to repeat the schedule.""" 28 | 29 | interval: Optional[int] = None 30 | """The interval of the schedule.""" 31 | 32 | minutes: Optional[int] = None 33 | """The minute of the hour to repeat the schedule.""" 34 | -------------------------------------------------------------------------------- /src/knockapi/types/schedule_repeat_rule_param.py: -------------------------------------------------------------------------------- 1 | # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | from __future__ import annotations 4 | 5 | from typing import List, Optional 6 | from typing_extensions import Literal, Required, Annotated, TypedDict 7 | 8 | from .._utils import PropertyInfo 9 | 10 | __all__ = ["ScheduleRepeatRuleParam"] 11 | 12 | 13 | class ScheduleRepeatRuleParam(TypedDict, total=False): 14 | frequency: Required[Literal["daily", "weekly", "monthly", "hourly"]] 15 | """The frequency of the schedule.""" 16 | 17 | _typename: Annotated[str, PropertyInfo(alias="__typename")] 18 | """The typename of the schema.""" 19 | 20 | day_of_month: Optional[int] 21 | """The day of the month to repeat the schedule.""" 22 | 23 | days: Optional[List[Literal["mon", "tue", "wed", "thu", "fri", "sat", "sun"]]] 24 | """The days of the week to repeat the schedule.""" 25 | 26 | hours: Optional[int] 27 | """The hour of the day to repeat the schedule.""" 28 | 29 | interval: int 30 | """The interval of the schedule.""" 31 | 32 | minutes: Optional[int] 33 | """The minute of the hour to repeat the schedule.""" 34 | -------------------------------------------------------------------------------- /src/knockapi/types/activity.py: -------------------------------------------------------------------------------- 1 | # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | from typing import Dict, Optional 4 | from datetime import datetime 5 | 6 | from pydantic import Field as FieldInfo 7 | 8 | from .._models import BaseModel 9 | from .recipient import Recipient 10 | 11 | __all__ = ["Activity"] 12 | 13 | 14 | class Activity(BaseModel): 15 | id: Optional[str] = None 16 | """Unique identifier for the activity.""" 17 | 18 | api_typename: Optional[str] = FieldInfo(alias="__typename", default=None) 19 | """The typename of the schema.""" 20 | 21 | actor: Optional[Recipient] = None 22 | """A recipient of a notification, which is either a user or an object.""" 23 | 24 | data: Optional[Dict[str, object]] = None 25 | """The workflow trigger `data` payload associated with the activity.""" 26 | 27 | inserted_at: Optional[datetime] = None 28 | """Timestamp when the activity was created.""" 29 | 30 | recipient: Optional[Recipient] = None 31 | """A recipient of a notification, which is either a user or an object.""" 32 | 33 | updated_at: Optional[datetime] = None 34 | """Timestamp when the activity was last updated.""" 35 | -------------------------------------------------------------------------------- /src/knockapi/types/providers/ms_team_list_channels_params.py: -------------------------------------------------------------------------------- 1 | # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | from __future__ import annotations 4 | 5 | from typing_extensions import Required, Annotated, TypedDict 6 | 7 | from ..._utils import PropertyInfo 8 | 9 | __all__ = ["MsTeamListChannelsParams", "QueryOptions"] 10 | 11 | 12 | class MsTeamListChannelsParams(TypedDict, total=False): 13 | ms_teams_tenant_object: Required[str] 14 | """A JSON encoded string containing the Microsoft Teams tenant object reference.""" 15 | 16 | team_id: Required[str] 17 | """Microsoft Teams team ID.""" 18 | 19 | query_options: QueryOptions 20 | 21 | 22 | class QueryOptions(TypedDict, total=False): 23 | filter: Annotated[str, PropertyInfo(alias="$filter")] 24 | """ 25 | [OData param](https://learn.microsoft.com/en-us/graph/query-parameters) passed 26 | to the Microsoft Graph API to filter channels. 27 | """ 28 | 29 | select: Annotated[str, PropertyInfo(alias="$select")] 30 | """ 31 | [OData param](https://learn.microsoft.com/en-us/graph/query-parameters) passed 32 | to the Microsoft Graph API to select specific properties. 33 | """ 34 | -------------------------------------------------------------------------------- /src/knockapi/types/recipients/discord_channel_data.py: -------------------------------------------------------------------------------- 1 | # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | from typing import List, Union 4 | from typing_extensions import TypeAlias 5 | 6 | from ..._models import BaseModel 7 | 8 | __all__ = [ 9 | "DiscordChannelData", 10 | "Connection", 11 | "ConnectionDiscordChannelConnection", 12 | "ConnectionDiscordIncomingWebhookConnection", 13 | "ConnectionDiscordIncomingWebhookConnectionIncomingWebhook", 14 | ] 15 | 16 | 17 | class ConnectionDiscordChannelConnection(BaseModel): 18 | channel_id: str 19 | """Discord channel ID.""" 20 | 21 | 22 | class ConnectionDiscordIncomingWebhookConnectionIncomingWebhook(BaseModel): 23 | url: str 24 | """Incoming webhook URL.""" 25 | 26 | 27 | class ConnectionDiscordIncomingWebhookConnection(BaseModel): 28 | incoming_webhook: ConnectionDiscordIncomingWebhookConnectionIncomingWebhook 29 | """Discord incoming webhook object.""" 30 | 31 | 32 | Connection: TypeAlias = Union[ConnectionDiscordChannelConnection, ConnectionDiscordIncomingWebhookConnection] 33 | 34 | 35 | class DiscordChannelData(BaseModel): 36 | connections: List[Connection] 37 | """List of Discord channel connections.""" 38 | -------------------------------------------------------------------------------- /src/knockapi/types/recipients/push_channel_data_devices_only_param.py: -------------------------------------------------------------------------------- 1 | # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | from __future__ import annotations 4 | 5 | from typing import Iterable, Optional 6 | from typing_extensions import Required, TypedDict 7 | 8 | __all__ = ["PushChannelDataDevicesOnlyParam", "Device"] 9 | 10 | 11 | class Device(TypedDict, total=False): 12 | token: Required[str] 13 | """The device token to send the push notification to.""" 14 | 15 | locale: Optional[str] 16 | """The locale of the object. 17 | 18 | Used for [message localization](/concepts/translations). 19 | """ 20 | 21 | timezone: Optional[str] 22 | """The timezone of the object. 23 | 24 | Must be a 25 | valid [tz database time zone string](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones). 26 | Used 27 | for [recurring schedules](/concepts/schedules#scheduling-workflows-with-recurring-schedules-for-recipients). 28 | """ 29 | 30 | 31 | class PushChannelDataDevicesOnlyParam(TypedDict, total=False): 32 | devices: Required[Iterable[Device]] 33 | """A list of devices. 34 | 35 | Each device contains a token, and optionally a locale and timezone. 36 | """ 37 | -------------------------------------------------------------------------------- /src/knockapi/types/providers/ms_team_list_channels_response.py: -------------------------------------------------------------------------------- 1 | # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | from typing import List, Optional 4 | 5 | from pydantic import Field as FieldInfo 6 | 7 | from ..._models import BaseModel 8 | 9 | __all__ = ["MsTeamListChannelsResponse", "MsTeamsChannel"] 10 | 11 | 12 | class MsTeamsChannel(BaseModel): 13 | id: str 14 | """Microsoft Teams channel ID.""" 15 | 16 | display_name: str = FieldInfo(alias="displayName") 17 | """Microsoft Teams channel name.""" 18 | 19 | created_date_time: Optional[str] = FieldInfo(alias="createdDateTime", default=None) 20 | """Microsoft Teams channel created date and time.""" 21 | 22 | description: Optional[str] = None 23 | """Microsoft Teams channel description.""" 24 | 25 | is_archived: Optional[bool] = FieldInfo(alias="isArchived", default=None) 26 | """Whether the Microsoft Teams channel is archived.""" 27 | 28 | membership_type: Optional[str] = FieldInfo(alias="membershipType", default=None) 29 | """Microsoft Teams channel membership type.""" 30 | 31 | 32 | class MsTeamListChannelsResponse(BaseModel): 33 | ms_teams_channels: List[MsTeamsChannel] 34 | """List of Microsoft Teams channels.""" 35 | -------------------------------------------------------------------------------- /src/knockapi/_resource.py: -------------------------------------------------------------------------------- 1 | # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | from __future__ import annotations 4 | 5 | import time 6 | from typing import TYPE_CHECKING 7 | 8 | import anyio 9 | 10 | if TYPE_CHECKING: 11 | from ._client import Knock, AsyncKnock 12 | 13 | 14 | class SyncAPIResource: 15 | _client: Knock 16 | 17 | def __init__(self, client: Knock) -> None: 18 | self._client = client 19 | self._get = client.get 20 | self._post = client.post 21 | self._patch = client.patch 22 | self._put = client.put 23 | self._delete = client.delete 24 | self._get_api_list = client.get_api_list 25 | 26 | def _sleep(self, seconds: float) -> None: 27 | time.sleep(seconds) 28 | 29 | 30 | class AsyncAPIResource: 31 | _client: AsyncKnock 32 | 33 | def __init__(self, client: AsyncKnock) -> None: 34 | self._client = client 35 | self._get = client.get 36 | self._post = client.post 37 | self._patch = client.patch 38 | self._put = client.put 39 | self._delete = client.delete 40 | self._get_api_list = client.get_api_list 41 | 42 | async def _sleep(self, seconds: float) -> None: 43 | await anyio.sleep(seconds) 44 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security Policy 2 | 3 | ## Reporting Security Issues 4 | 5 | This SDK is generated by [Stainless Software Inc](http://stainless.com). Stainless takes security seriously, and encourages you to report any security vulnerability promptly so that appropriate action can be taken. 6 | 7 | To report a security issue, please contact the Stainless team at security@stainless.com. 8 | 9 | ## Responsible Disclosure 10 | 11 | We appreciate the efforts of security researchers and individuals who help us maintain the security of 12 | SDKs we generate. If you believe you have found a security vulnerability, please adhere to responsible 13 | disclosure practices by allowing us a reasonable amount of time to investigate and address the issue 14 | before making any information public. 15 | 16 | ## Reporting Non-SDK Related Security Issues 17 | 18 | If you encounter security issues that are not directly related to SDKs but pertain to the services 19 | or products provided by Knock, please follow the respective company's security reporting guidelines. 20 | 21 | ### Knock Terms and Policies 22 | 23 | Please contact security@knock.app for any questions or concerns regarding the security of our services. 24 | 25 | --- 26 | 27 | Thank you for helping us keep the SDKs and systems they interact with secure. 28 | -------------------------------------------------------------------------------- /src/knockapi/types/shared_params/condition.py: -------------------------------------------------------------------------------- 1 | # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | from __future__ import annotations 4 | 5 | from typing import Optional 6 | from typing_extensions import Literal, Required, TypedDict 7 | 8 | __all__ = ["Condition"] 9 | 10 | 11 | class Condition(TypedDict, total=False): 12 | argument: Required[Optional[str]] 13 | """The argument value to compare against in the condition.""" 14 | 15 | operator: Required[ 16 | Literal[ 17 | "equal_to", 18 | "not_equal_to", 19 | "greater_than", 20 | "less_than", 21 | "greater_than_or_equal_to", 22 | "less_than_or_equal_to", 23 | "contains", 24 | "not_contains", 25 | "empty", 26 | "not_empty", 27 | "contains_all", 28 | "is_timestamp", 29 | "is_not_timestamp", 30 | "is_timestamp_after", 31 | "is_timestamp_before", 32 | "is_timestamp_between", 33 | "is_audience_member", 34 | "is_not_audience_member", 35 | ] 36 | ] 37 | """The operator to use in the condition evaluation.""" 38 | 39 | variable: Required[str] 40 | """The variable to be evaluated in the condition.""" 41 | -------------------------------------------------------------------------------- /src/knockapi/types/recipients/discord_channel_data_param.py: -------------------------------------------------------------------------------- 1 | # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | from __future__ import annotations 4 | 5 | from typing import Union, Iterable 6 | from typing_extensions import Required, TypeAlias, TypedDict 7 | 8 | __all__ = [ 9 | "DiscordChannelDataParam", 10 | "Connection", 11 | "ConnectionDiscordChannelConnection", 12 | "ConnectionDiscordIncomingWebhookConnection", 13 | "ConnectionDiscordIncomingWebhookConnectionIncomingWebhook", 14 | ] 15 | 16 | 17 | class ConnectionDiscordChannelConnection(TypedDict, total=False): 18 | channel_id: Required[str] 19 | """Discord channel ID.""" 20 | 21 | 22 | class ConnectionDiscordIncomingWebhookConnectionIncomingWebhook(TypedDict, total=False): 23 | url: Required[str] 24 | """Incoming webhook URL.""" 25 | 26 | 27 | class ConnectionDiscordIncomingWebhookConnection(TypedDict, total=False): 28 | incoming_webhook: Required[ConnectionDiscordIncomingWebhookConnectionIncomingWebhook] 29 | """Discord incoming webhook object.""" 30 | 31 | 32 | Connection: TypeAlias = Union[ConnectionDiscordChannelConnection, ConnectionDiscordIncomingWebhookConnection] 33 | 34 | 35 | class DiscordChannelDataParam(TypedDict, total=False): 36 | connections: Required[Iterable[Connection]] 37 | """List of Discord channel connections.""" 38 | -------------------------------------------------------------------------------- /src/knockapi/_utils/_compat.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | import sys 4 | import typing_extensions 5 | from typing import Any, Type, Union, Literal, Optional 6 | from datetime import date, datetime 7 | from typing_extensions import get_args as _get_args, get_origin as _get_origin 8 | 9 | from .._types import StrBytesIntFloat 10 | from ._datetime_parse import parse_date as _parse_date, parse_datetime as _parse_datetime 11 | 12 | _LITERAL_TYPES = {Literal, typing_extensions.Literal} 13 | 14 | 15 | def get_args(tp: type[Any]) -> tuple[Any, ...]: 16 | return _get_args(tp) 17 | 18 | 19 | def get_origin(tp: type[Any]) -> type[Any] | None: 20 | return _get_origin(tp) 21 | 22 | 23 | def is_union(tp: Optional[Type[Any]]) -> bool: 24 | if sys.version_info < (3, 10): 25 | return tp is Union # type: ignore[comparison-overlap] 26 | else: 27 | import types 28 | 29 | return tp is Union or tp is types.UnionType 30 | 31 | 32 | def is_typeddict(tp: Type[Any]) -> bool: 33 | return typing_extensions.is_typeddict(tp) 34 | 35 | 36 | def is_literal_type(tp: Type[Any]) -> bool: 37 | return get_origin(tp) in _LITERAL_TYPES 38 | 39 | 40 | def parse_date(value: Union[date, StrBytesIntFloat]) -> date: 41 | return _parse_date(value) 42 | 43 | 44 | def parse_datetime(value: Union[datetime, StrBytesIntFloat]) -> datetime: 45 | return _parse_datetime(value) 46 | -------------------------------------------------------------------------------- /src/knockapi/types/recipients/slack_channel_data.py: -------------------------------------------------------------------------------- 1 | # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | from typing import List, Union, Optional 4 | from typing_extensions import TypeAlias 5 | 6 | from ..._models import BaseModel 7 | 8 | __all__ = [ 9 | "SlackChannelData", 10 | "Connection", 11 | "ConnectionSlackTokenConnection", 12 | "ConnectionSlackIncomingWebhookConnection", 13 | "Token", 14 | ] 15 | 16 | 17 | class ConnectionSlackTokenConnection(BaseModel): 18 | access_token: Optional[str] = None 19 | """A Slack access token.""" 20 | 21 | channel_id: Optional[str] = None 22 | """A Slack channel ID from the Slack provider.""" 23 | 24 | user_id: Optional[str] = None 25 | """A Slack user ID from the Slack provider.""" 26 | 27 | 28 | class ConnectionSlackIncomingWebhookConnection(BaseModel): 29 | url: str 30 | """The URL of the incoming webhook for a Slack connection.""" 31 | 32 | 33 | Connection: TypeAlias = Union[ConnectionSlackTokenConnection, ConnectionSlackIncomingWebhookConnection] 34 | 35 | 36 | class Token(BaseModel): 37 | access_token: Optional[str] = None 38 | """A Slack access token.""" 39 | 40 | 41 | class SlackChannelData(BaseModel): 42 | connections: List[Connection] 43 | """List of Slack channel connections.""" 44 | 45 | token: Optional[Token] = None 46 | """A Slack connection token.""" 47 | -------------------------------------------------------------------------------- /.devcontainer/devcontainer.json: -------------------------------------------------------------------------------- 1 | // For format details, see https://aka.ms/devcontainer.json. For config options, see the 2 | // README at: https://github.com/devcontainers/templates/tree/main/src/debian 3 | { 4 | "name": "Debian", 5 | "build": { 6 | "dockerfile": "Dockerfile", 7 | "context": ".." 8 | }, 9 | 10 | "postStartCommand": "rye sync --all-features", 11 | 12 | "customizations": { 13 | "vscode": { 14 | "extensions": [ 15 | "ms-python.python" 16 | ], 17 | "settings": { 18 | "terminal.integrated.shell.linux": "/bin/bash", 19 | "python.pythonPath": ".venv/bin/python", 20 | "python.defaultInterpreterPath": ".venv/bin/python", 21 | "python.typeChecking": "basic", 22 | "terminal.integrated.env.linux": { 23 | "PATH": "/home/vscode/.rye/shims:${env:PATH}" 24 | } 25 | } 26 | } 27 | }, 28 | "features": { 29 | "ghcr.io/devcontainers/features/node:1": {} 30 | } 31 | 32 | // Features to add to the dev container. More info: https://containers.dev/features. 33 | // "features": {}, 34 | 35 | // Use 'forwardPorts' to make a list of ports inside the container available locally. 36 | // "forwardPorts": [], 37 | 38 | // Configure tool-specific properties. 39 | // "customizations": {}, 40 | 41 | // Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root. 42 | // "remoteUser": "root" 43 | } 44 | -------------------------------------------------------------------------------- /src/knockapi/types/providers/__init__.py: -------------------------------------------------------------------------------- 1 | # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | from __future__ import annotations 4 | 5 | from .slack_check_auth_params import SlackCheckAuthParams as SlackCheckAuthParams 6 | from .ms_team_check_auth_params import MsTeamCheckAuthParams as MsTeamCheckAuthParams 7 | from .ms_team_list_teams_params import MsTeamListTeamsParams as MsTeamListTeamsParams 8 | from .slack_check_auth_response import SlackCheckAuthResponse as SlackCheckAuthResponse 9 | from .slack_list_channels_params import SlackListChannelsParams as SlackListChannelsParams 10 | from .slack_revoke_access_params import SlackRevokeAccessParams as SlackRevokeAccessParams 11 | from .ms_team_check_auth_response import MsTeamCheckAuthResponse as MsTeamCheckAuthResponse 12 | from .ms_team_list_teams_response import MsTeamListTeamsResponse as MsTeamListTeamsResponse 13 | from .ms_team_list_channels_params import MsTeamListChannelsParams as MsTeamListChannelsParams 14 | from .ms_team_revoke_access_params import MsTeamRevokeAccessParams as MsTeamRevokeAccessParams 15 | from .slack_list_channels_response import SlackListChannelsResponse as SlackListChannelsResponse 16 | from .slack_revoke_access_response import SlackRevokeAccessResponse as SlackRevokeAccessResponse 17 | from .ms_team_list_channels_response import MsTeamListChannelsResponse as MsTeamListChannelsResponse 18 | from .ms_team_revoke_access_response import MsTeamRevokeAccessResponse as MsTeamRevokeAccessResponse 19 | -------------------------------------------------------------------------------- /src/knockapi/types/recipients/aws_sns_push_channel_data_devices_only_param.py: -------------------------------------------------------------------------------- 1 | # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | from __future__ import annotations 4 | 5 | from typing import Iterable, Optional 6 | from typing_extensions import Required, TypedDict 7 | 8 | __all__ = ["AwsSnsPushChannelDataDevicesOnlyParam", "Device"] 9 | 10 | 11 | class Device(TypedDict, total=False): 12 | target_arn: Required[str] 13 | """ 14 | The ARN of a platform endpoint associated with a platform application and a 15 | device token. See 16 | [Setting up an Amazon SNS platform endpoint for mobile notifications](https://docs.aws.amazon.com/sns/latest/dg/mobile-platform-endpoint.html). 17 | """ 18 | 19 | locale: Optional[str] 20 | """The locale of the object. 21 | 22 | Used for [message localization](/concepts/translations). 23 | """ 24 | 25 | timezone: Optional[str] 26 | """The timezone of the object. 27 | 28 | Must be a 29 | valid [tz database time zone string](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones). 30 | Used 31 | for [recurring schedules](/concepts/schedules#scheduling-workflows-with-recurring-schedules-for-recipients). 32 | """ 33 | 34 | 35 | class AwsSnsPushChannelDataDevicesOnlyParam(TypedDict, total=False): 36 | devices: Required[Iterable[Device]] 37 | """A list of devices. 38 | 39 | Each device contains a target_arn, and optionally a locale and timezone. 40 | """ 41 | -------------------------------------------------------------------------------- /src/knockapi/types/recipients/slack_channel_data_param.py: -------------------------------------------------------------------------------- 1 | # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | from __future__ import annotations 4 | 5 | from typing import Union, Iterable, Optional 6 | from typing_extensions import Required, TypeAlias, TypedDict 7 | 8 | __all__ = [ 9 | "SlackChannelDataParam", 10 | "Connection", 11 | "ConnectionSlackTokenConnection", 12 | "ConnectionSlackIncomingWebhookConnection", 13 | "Token", 14 | ] 15 | 16 | 17 | class ConnectionSlackTokenConnection(TypedDict, total=False): 18 | access_token: Optional[str] 19 | """A Slack access token.""" 20 | 21 | channel_id: Optional[str] 22 | """A Slack channel ID from the Slack provider.""" 23 | 24 | user_id: Optional[str] 25 | """A Slack user ID from the Slack provider.""" 26 | 27 | 28 | class ConnectionSlackIncomingWebhookConnection(TypedDict, total=False): 29 | url: Required[str] 30 | """The URL of the incoming webhook for a Slack connection.""" 31 | 32 | 33 | Connection: TypeAlias = Union[ConnectionSlackTokenConnection, ConnectionSlackIncomingWebhookConnection] 34 | 35 | 36 | class Token(TypedDict, total=False): 37 | access_token: Required[Optional[str]] 38 | """A Slack access token.""" 39 | 40 | 41 | class SlackChannelDataParam(TypedDict, total=False): 42 | connections: Required[Iterable[Connection]] 43 | """List of Slack channel connections.""" 44 | 45 | token: Optional[Token] 46 | """A Slack connection token.""" 47 | -------------------------------------------------------------------------------- /src/knockapi/types/recipients/inline_channel_data_request_param.py: -------------------------------------------------------------------------------- 1 | # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | from __future__ import annotations 4 | 5 | from typing import Dict, Union 6 | from typing_extensions import TypeAlias 7 | 8 | from .slack_channel_data_param import SlackChannelDataParam 9 | from .discord_channel_data_param import DiscordChannelDataParam 10 | from .ms_teams_channel_data_param import MsTeamsChannelDataParam 11 | from .push_channel_data_tokens_only_param import PushChannelDataTokensOnlyParam 12 | from .push_channel_data_devices_only_param import PushChannelDataDevicesOnlyParam 13 | from .aws_sns_push_channel_data_devices_only_param import AwsSnsPushChannelDataDevicesOnlyParam 14 | from .one_signal_channel_data_player_ids_only_param import OneSignalChannelDataPlayerIDsOnlyParam 15 | from .aws_sns_push_channel_data_target_arns_only_param import AwsSnsPushChannelDataTargetArnsOnlyParam 16 | 17 | __all__ = ["InlineChannelDataRequestParam", "InlineChannelDataRequestParamItem"] 18 | 19 | InlineChannelDataRequestParamItem: TypeAlias = Union[ 20 | PushChannelDataTokensOnlyParam, 21 | PushChannelDataDevicesOnlyParam, 22 | AwsSnsPushChannelDataTargetArnsOnlyParam, 23 | AwsSnsPushChannelDataDevicesOnlyParam, 24 | OneSignalChannelDataPlayerIDsOnlyParam, 25 | SlackChannelDataParam, 26 | MsTeamsChannelDataParam, 27 | DiscordChannelDataParam, 28 | ] 29 | 30 | InlineChannelDataRequestParam: TypeAlias = Dict[str, InlineChannelDataRequestParamItem] 31 | -------------------------------------------------------------------------------- /src/knockapi/types/object_set_params.py: -------------------------------------------------------------------------------- 1 | # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | from __future__ import annotations 4 | 5 | from typing import Optional 6 | from typing_extensions import TypedDict 7 | 8 | from .recipients.inline_channel_data_request_param import InlineChannelDataRequestParam 9 | from .recipients.inline_preference_set_request_param import InlinePreferenceSetRequestParam 10 | 11 | __all__ = ["ObjectSetParams"] 12 | 13 | 14 | class ObjectSetParams(TypedDict, total=False): 15 | channel_data: InlineChannelDataRequestParam 16 | """A request to set channel data for a type of channel inline.""" 17 | 18 | locale: Optional[str] 19 | """The locale of the object. 20 | 21 | Used for [message localization](/concepts/translations). 22 | """ 23 | 24 | name: Optional[str] 25 | """An optional name for the object.""" 26 | 27 | preferences: InlinePreferenceSetRequestParam 28 | """Inline set preferences for a recipient, where the key is the preference set id. 29 | 30 | Preferences that are set inline will be merged into any existing preferences 31 | rather than replacing them. 32 | """ 33 | 34 | timezone: Optional[str] 35 | """The timezone of the object. 36 | 37 | Must be a 38 | valid [tz database time zone string](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones). 39 | Used 40 | for [recurring schedules](/concepts/schedules#scheduling-workflows-with-recurring-schedules-for-recipients). 41 | """ 42 | -------------------------------------------------------------------------------- /src/knockapi/_utils/_reflection.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | import inspect 4 | from typing import Any, Callable 5 | 6 | 7 | def function_has_argument(func: Callable[..., Any], arg_name: str) -> bool: 8 | """Returns whether or not the given function has a specific parameter""" 9 | sig = inspect.signature(func) 10 | return arg_name in sig.parameters 11 | 12 | 13 | def assert_signatures_in_sync( 14 | source_func: Callable[..., Any], 15 | check_func: Callable[..., Any], 16 | *, 17 | exclude_params: set[str] = set(), 18 | ) -> None: 19 | """Ensure that the signature of the second function matches the first.""" 20 | 21 | check_sig = inspect.signature(check_func) 22 | source_sig = inspect.signature(source_func) 23 | 24 | errors: list[str] = [] 25 | 26 | for name, source_param in source_sig.parameters.items(): 27 | if name in exclude_params: 28 | continue 29 | 30 | custom_param = check_sig.parameters.get(name) 31 | if not custom_param: 32 | errors.append(f"the `{name}` param is missing") 33 | continue 34 | 35 | if custom_param.annotation != source_param.annotation: 36 | errors.append( 37 | f"types for the `{name}` param are do not match; source={repr(source_param.annotation)} checking={repr(custom_param.annotation)}" 38 | ) 39 | continue 40 | 41 | if errors: 42 | raise AssertionError(f"{len(errors)} errors encountered when comparing signatures:\n\n" + "\n\n".join(errors)) 43 | -------------------------------------------------------------------------------- /src/knockapi/types/object_list_subscriptions_params.py: -------------------------------------------------------------------------------- 1 | # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | from __future__ import annotations 4 | 5 | from typing import List, Iterable 6 | from typing_extensions import Literal, TypedDict 7 | 8 | from .._types import SequenceNotStr 9 | from .recipient_reference_param import RecipientReferenceParam 10 | 11 | __all__ = ["ObjectListSubscriptionsParams", "Object"] 12 | 13 | 14 | class ObjectListSubscriptionsParams(TypedDict, total=False): 15 | after: str 16 | """The cursor to fetch entries after.""" 17 | 18 | before: str 19 | """The cursor to fetch entries before.""" 20 | 21 | include: List[Literal["preferences"]] 22 | """Additional fields to include in the response.""" 23 | 24 | mode: Literal["recipient", "object"] 25 | """Mode of the request. 26 | 27 | `recipient` to list the objects that the provided object is subscribed to, 28 | `object` to list the recipients that subscribe to the provided object. 29 | """ 30 | 31 | objects: Iterable[Object] 32 | """Objects to filter by (only used if mode is `recipient`).""" 33 | 34 | page_size: int 35 | """The number of items per page (defaults to 50).""" 36 | 37 | recipients: SequenceNotStr[RecipientReferenceParam] 38 | """Recipients to filter by (only used if mode is `object`).""" 39 | 40 | 41 | class Object(TypedDict, total=False): 42 | id: str 43 | """An identifier for the recipient object.""" 44 | 45 | collection: str 46 | """The collection the recipient object belongs to.""" 47 | -------------------------------------------------------------------------------- /src/knockapi/types/user_set_channel_data_params.py: -------------------------------------------------------------------------------- 1 | # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | from __future__ import annotations 4 | 5 | from typing import Union 6 | from typing_extensions import Required, TypeAlias, TypedDict 7 | 8 | from .recipients.slack_channel_data_param import SlackChannelDataParam 9 | from .recipients.discord_channel_data_param import DiscordChannelDataParam 10 | from .recipients.ms_teams_channel_data_param import MsTeamsChannelDataParam 11 | from .recipients.push_channel_data_tokens_only_param import PushChannelDataTokensOnlyParam 12 | from .recipients.push_channel_data_devices_only_param import PushChannelDataDevicesOnlyParam 13 | from .recipients.aws_sns_push_channel_data_devices_only_param import AwsSnsPushChannelDataDevicesOnlyParam 14 | from .recipients.one_signal_channel_data_player_ids_only_param import OneSignalChannelDataPlayerIDsOnlyParam 15 | from .recipients.aws_sns_push_channel_data_target_arns_only_param import AwsSnsPushChannelDataTargetArnsOnlyParam 16 | 17 | __all__ = ["UserSetChannelDataParams", "Data"] 18 | 19 | 20 | class UserSetChannelDataParams(TypedDict, total=False): 21 | data: Required[Data] 22 | """Channel data for a given channel type.""" 23 | 24 | 25 | Data: TypeAlias = Union[ 26 | PushChannelDataTokensOnlyParam, 27 | PushChannelDataDevicesOnlyParam, 28 | AwsSnsPushChannelDataTargetArnsOnlyParam, 29 | AwsSnsPushChannelDataDevicesOnlyParam, 30 | OneSignalChannelDataPlayerIDsOnlyParam, 31 | SlackChannelDataParam, 32 | MsTeamsChannelDataParam, 33 | DiscordChannelDataParam, 34 | ] 35 | -------------------------------------------------------------------------------- /src/knockapi/types/object_set_channel_data_params.py: -------------------------------------------------------------------------------- 1 | # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | from __future__ import annotations 4 | 5 | from typing import Union 6 | from typing_extensions import Required, TypeAlias, TypedDict 7 | 8 | from .recipients.slack_channel_data_param import SlackChannelDataParam 9 | from .recipients.discord_channel_data_param import DiscordChannelDataParam 10 | from .recipients.ms_teams_channel_data_param import MsTeamsChannelDataParam 11 | from .recipients.push_channel_data_tokens_only_param import PushChannelDataTokensOnlyParam 12 | from .recipients.push_channel_data_devices_only_param import PushChannelDataDevicesOnlyParam 13 | from .recipients.aws_sns_push_channel_data_devices_only_param import AwsSnsPushChannelDataDevicesOnlyParam 14 | from .recipients.one_signal_channel_data_player_ids_only_param import OneSignalChannelDataPlayerIDsOnlyParam 15 | from .recipients.aws_sns_push_channel_data_target_arns_only_param import AwsSnsPushChannelDataTargetArnsOnlyParam 16 | 17 | __all__ = ["ObjectSetChannelDataParams", "Data"] 18 | 19 | 20 | class ObjectSetChannelDataParams(TypedDict, total=False): 21 | data: Required[Data] 22 | """Channel data for a given channel type.""" 23 | 24 | 25 | Data: TypeAlias = Union[ 26 | PushChannelDataTokensOnlyParam, 27 | PushChannelDataDevicesOnlyParam, 28 | AwsSnsPushChannelDataTargetArnsOnlyParam, 29 | AwsSnsPushChannelDataDevicesOnlyParam, 30 | OneSignalChannelDataPlayerIDsOnlyParam, 31 | SlackChannelDataParam, 32 | MsTeamsChannelDataParam, 33 | DiscordChannelDataParam, 34 | ] 35 | -------------------------------------------------------------------------------- /src/knockapi/types/providers/slack_list_channels_params.py: -------------------------------------------------------------------------------- 1 | # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | from __future__ import annotations 4 | 5 | from typing_extensions import Required, TypedDict 6 | 7 | __all__ = ["SlackListChannelsParams", "QueryOptions"] 8 | 9 | 10 | class SlackListChannelsParams(TypedDict, total=False): 11 | access_token_object: Required[str] 12 | """A JSON encoded string containing the access token object reference.""" 13 | 14 | query_options: QueryOptions 15 | 16 | 17 | class QueryOptions(TypedDict, total=False): 18 | cursor: str 19 | """ 20 | Paginate through collections of data by setting the cursor parameter to a 21 | next_cursor attribute returned by a previous request's response_metadata. 22 | Default value fetches the first "page" of the collection. 23 | """ 24 | 25 | exclude_archived: bool 26 | """Set to true to exclude archived channels from the list. 27 | 28 | Defaults to `true` when not explicitly provided. 29 | """ 30 | 31 | limit: int 32 | """The maximum number of channels to return. Defaults to 200.""" 33 | 34 | team_id: str 35 | """Encoded team ID (T1234) to list channels in, required if org token is used.""" 36 | 37 | types: str 38 | """ 39 | Mix and match channel types by providing a comma-separated list of any 40 | combination of public_channel, private_channel, mpim, im. Defaults to 41 | `"public_channel,private_channel"`. If the user's Slack ID is unavailable, this 42 | option is ignored and only public channels are returned. 43 | """ 44 | -------------------------------------------------------------------------------- /release-please-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "packages": { 3 | ".": {} 4 | }, 5 | "$schema": "https://raw.githubusercontent.com/stainless-api/release-please/main/schemas/config.json", 6 | "include-v-in-tag": true, 7 | "include-component-in-tag": false, 8 | "versioning": "prerelease", 9 | "prerelease": true, 10 | "bump-minor-pre-major": true, 11 | "bump-patch-for-minor-pre-major": false, 12 | "pull-request-header": "Automated Release PR", 13 | "pull-request-title-pattern": "release: ${version}", 14 | "changelog-sections": [ 15 | { 16 | "type": "feat", 17 | "section": "Features" 18 | }, 19 | { 20 | "type": "fix", 21 | "section": "Bug Fixes" 22 | }, 23 | { 24 | "type": "perf", 25 | "section": "Performance Improvements" 26 | }, 27 | { 28 | "type": "revert", 29 | "section": "Reverts" 30 | }, 31 | { 32 | "type": "chore", 33 | "section": "Chores" 34 | }, 35 | { 36 | "type": "docs", 37 | "section": "Documentation" 38 | }, 39 | { 40 | "type": "style", 41 | "section": "Styles" 42 | }, 43 | { 44 | "type": "refactor", 45 | "section": "Refactors" 46 | }, 47 | { 48 | "type": "test", 49 | "section": "Tests", 50 | "hidden": true 51 | }, 52 | { 53 | "type": "build", 54 | "section": "Build System" 55 | }, 56 | { 57 | "type": "ci", 58 | "section": "Continuous Integration", 59 | "hidden": true 60 | } 61 | ], 62 | "release-type": "python", 63 | "extra-files": [ 64 | "src/knockapi/_version.py" 65 | ] 66 | } -------------------------------------------------------------------------------- /src/knockapi/types/inline_object_request_param.py: -------------------------------------------------------------------------------- 1 | # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | from __future__ import annotations 4 | 5 | from typing import Dict, Union, Optional 6 | from datetime import datetime 7 | from typing_extensions import Required, Annotated, TypeAlias, TypedDict 8 | 9 | from .._utils import PropertyInfo 10 | from .recipients.inline_channel_data_request_param import InlineChannelDataRequestParam 11 | from .recipients.inline_preference_set_request_param import InlinePreferenceSetRequestParam 12 | 13 | __all__ = ["InlineObjectRequestParam"] 14 | 15 | 16 | class InlineObjectRequestParamTyped(TypedDict, total=False): 17 | id: Required[str] 18 | """Unique identifier for the object.""" 19 | 20 | collection: Required[str] 21 | """The collection this object belongs to.""" 22 | 23 | channel_data: Optional[InlineChannelDataRequestParam] 24 | """A request to set channel data for a type of channel inline.""" 25 | 26 | created_at: Annotated[Union[str, datetime, None], PropertyInfo(format="iso8601")] 27 | """Timestamp when the resource was created.""" 28 | 29 | name: Optional[str] 30 | """An optional name for the object.""" 31 | 32 | preferences: Optional[InlinePreferenceSetRequestParam] 33 | """Inline set preferences for a recipient, where the key is the preference set id. 34 | 35 | Preferences that are set inline will be merged into any existing preferences 36 | rather than replacing them. 37 | """ 38 | 39 | 40 | InlineObjectRequestParam: TypeAlias = Union[InlineObjectRequestParamTyped, Dict[str, object]] 41 | -------------------------------------------------------------------------------- /src/knockapi/types/objects/bulk_set_params.py: -------------------------------------------------------------------------------- 1 | # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | from __future__ import annotations 4 | 5 | from typing import Dict, Union, Iterable, Optional 6 | from datetime import datetime 7 | from typing_extensions import Required, Annotated, TypeAlias, TypedDict 8 | 9 | from ..._utils import PropertyInfo 10 | from ..recipients.inline_channel_data_request_param import InlineChannelDataRequestParam 11 | from ..recipients.inline_preference_set_request_param import InlinePreferenceSetRequestParam 12 | 13 | __all__ = ["BulkSetParams", "Object"] 14 | 15 | 16 | class BulkSetParams(TypedDict, total=False): 17 | objects: Required[Iterable[Object]] 18 | """A list of objects.""" 19 | 20 | 21 | class ObjectTyped(TypedDict, total=False): 22 | id: Required[str] 23 | """Unique identifier for the object.""" 24 | 25 | channel_data: Optional[InlineChannelDataRequestParam] 26 | """A request to set channel data for a type of channel inline.""" 27 | 28 | created_at: Annotated[Union[str, datetime, None], PropertyInfo(format="iso8601")] 29 | """Timestamp when the resource was created.""" 30 | 31 | name: Optional[str] 32 | """An optional name for the object.""" 33 | 34 | preferences: Optional[InlinePreferenceSetRequestParam] 35 | """Inline set preferences for a recipient, where the key is the preference set id. 36 | 37 | Preferences that are set inline will be merged into any existing preferences 38 | rather than replacing them. 39 | """ 40 | 41 | 42 | Object: TypeAlias = Union[ObjectTyped, Dict[str, object]] 43 | -------------------------------------------------------------------------------- /src/knockapi/types/providers/ms_team_list_teams_params.py: -------------------------------------------------------------------------------- 1 | # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | from __future__ import annotations 4 | 5 | from typing_extensions import Required, Annotated, TypedDict 6 | 7 | from ..._utils import PropertyInfo 8 | 9 | __all__ = ["MsTeamListTeamsParams", "QueryOptions"] 10 | 11 | 12 | class MsTeamListTeamsParams(TypedDict, total=False): 13 | ms_teams_tenant_object: Required[str] 14 | """A JSON encoded string containing the Microsoft Teams tenant object reference.""" 15 | 16 | query_options: QueryOptions 17 | 18 | 19 | class QueryOptions(TypedDict, total=False): 20 | filter: Annotated[str, PropertyInfo(alias="$filter")] 21 | """ 22 | [OData param](https://learn.microsoft.com/en-us/graph/query-parameters) passed 23 | to the Microsoft Graph API to filter teams. 24 | """ 25 | 26 | select: Annotated[str, PropertyInfo(alias="$select")] 27 | """ 28 | [OData param](https://learn.microsoft.com/en-us/graph/query-parameters) passed 29 | to the Microsoft Graph API to select fields on a team. 30 | """ 31 | 32 | skiptoken: Annotated[str, PropertyInfo(alias="$skiptoken")] 33 | """ 34 | [OData param](https://learn.microsoft.com/en-us/graph/query-parameters) passed 35 | to the Microsoft Graph API to retrieve the next page of results. 36 | """ 37 | 38 | top: Annotated[int, PropertyInfo(alias="$top")] 39 | """ 40 | [OData param](https://learn.microsoft.com/en-us/graph/query-parameters) passed 41 | to the Microsoft Graph API to limit the number of teams returned. 42 | """ 43 | -------------------------------------------------------------------------------- /src/knockapi/types/recipients/preference_set_channel_types_param.py: -------------------------------------------------------------------------------- 1 | # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | from __future__ import annotations 4 | 5 | from typing import Union 6 | from typing_extensions import TypeAlias, TypedDict 7 | 8 | from .preference_set_channel_type_setting_param import PreferenceSetChannelTypeSettingParam 9 | 10 | __all__ = ["PreferenceSetChannelTypesParam", "Chat", "Email", "HTTP", "InAppFeed", "Push", "SMS"] 11 | 12 | Chat: TypeAlias = Union[bool, PreferenceSetChannelTypeSettingParam] 13 | 14 | Email: TypeAlias = Union[bool, PreferenceSetChannelTypeSettingParam] 15 | 16 | HTTP: TypeAlias = Union[bool, PreferenceSetChannelTypeSettingParam] 17 | 18 | InAppFeed: TypeAlias = Union[bool, PreferenceSetChannelTypeSettingParam] 19 | 20 | Push: TypeAlias = Union[bool, PreferenceSetChannelTypeSettingParam] 21 | 22 | SMS: TypeAlias = Union[bool, PreferenceSetChannelTypeSettingParam] 23 | 24 | 25 | class PreferenceSetChannelTypesParam(TypedDict, total=False): 26 | chat: Chat 27 | """Whether the channel type is enabled for the preference set.""" 28 | 29 | email: Email 30 | """Whether the channel type is enabled for the preference set.""" 31 | 32 | http: HTTP 33 | """Whether the channel type is enabled for the preference set.""" 34 | 35 | in_app_feed: InAppFeed 36 | """Whether the channel type is enabled for the preference set.""" 37 | 38 | push: Push 39 | """Whether the channel type is enabled for the preference set.""" 40 | 41 | sms: SMS 42 | """Whether the channel type is enabled for the preference set.""" 43 | -------------------------------------------------------------------------------- /src/knockapi/types/message_event.py: -------------------------------------------------------------------------------- 1 | # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | from typing import Dict, Optional 4 | from datetime import datetime 5 | from typing_extensions import Literal 6 | 7 | from pydantic import Field as FieldInfo 8 | 9 | from .._models import BaseModel 10 | from .recipient_reference import RecipientReference 11 | 12 | __all__ = ["MessageEvent"] 13 | 14 | 15 | class MessageEvent(BaseModel): 16 | id: str 17 | """The unique identifier for the message event.""" 18 | 19 | api_typename: str = FieldInfo(alias="__typename") 20 | """The typename of the schema.""" 21 | 22 | inserted_at: datetime 23 | """Timestamp when the event was created.""" 24 | 25 | recipient: RecipientReference 26 | """ 27 | A reference to a recipient, either a user identifier (string) or an object 28 | reference (ID, collection). 29 | """ 30 | 31 | type: Literal[ 32 | "message.archived", 33 | "message.bounced", 34 | "message.delivered", 35 | "message.delivery_attempted", 36 | "message.interacted", 37 | "message.link_clicked", 38 | "message.not_sent", 39 | "message.queued", 40 | "message.read", 41 | "message.seen", 42 | "message.sent", 43 | "message.unarchived", 44 | "message.undelivered", 45 | "message.unread", 46 | "message.unseen", 47 | ] 48 | """The type of event that occurred.""" 49 | 50 | data: Optional[Dict[str, object]] = None 51 | """The data associated with the message event. Only present for some event types.""" 52 | -------------------------------------------------------------------------------- /src/knockapi/types/recipients/preference_set_channel_types.py: -------------------------------------------------------------------------------- 1 | # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | from typing import Union, Optional 4 | from typing_extensions import TypeAlias 5 | 6 | from ..._models import BaseModel 7 | from .preference_set_channel_type_setting import PreferenceSetChannelTypeSetting 8 | 9 | __all__ = ["PreferenceSetChannelTypes", "Chat", "Email", "HTTP", "InAppFeed", "Push", "SMS"] 10 | 11 | Chat: TypeAlias = Union[bool, PreferenceSetChannelTypeSetting] 12 | 13 | Email: TypeAlias = Union[bool, PreferenceSetChannelTypeSetting] 14 | 15 | HTTP: TypeAlias = Union[bool, PreferenceSetChannelTypeSetting] 16 | 17 | InAppFeed: TypeAlias = Union[bool, PreferenceSetChannelTypeSetting] 18 | 19 | Push: TypeAlias = Union[bool, PreferenceSetChannelTypeSetting] 20 | 21 | SMS: TypeAlias = Union[bool, PreferenceSetChannelTypeSetting] 22 | 23 | 24 | class PreferenceSetChannelTypes(BaseModel): 25 | chat: Optional[Chat] = None 26 | """Whether the channel type is enabled for the preference set.""" 27 | 28 | email: Optional[Email] = None 29 | """Whether the channel type is enabled for the preference set.""" 30 | 31 | http: Optional[HTTP] = None 32 | """Whether the channel type is enabled for the preference set.""" 33 | 34 | in_app_feed: Optional[InAppFeed] = None 35 | """Whether the channel type is enabled for the preference set.""" 36 | 37 | push: Optional[Push] = None 38 | """Whether the channel type is enabled for the preference set.""" 39 | 40 | sms: Optional[SMS] = None 41 | """Whether the channel type is enabled for the preference set.""" 42 | -------------------------------------------------------------------------------- /src/knockapi/types/users/__init__.py: -------------------------------------------------------------------------------- 1 | # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | from __future__ import annotations 4 | 5 | from .bulk_delete_params import BulkDeleteParams as BulkDeleteParams 6 | from .bulk_identify_params import BulkIdentifyParams as BulkIdentifyParams 7 | from .feed_list_items_params import FeedListItemsParams as FeedListItemsParams 8 | from .feed_list_items_response import FeedListItemsResponse as FeedListItemsResponse 9 | from .guide_get_channel_params import GuideGetChannelParams as GuideGetChannelParams 10 | from .feed_get_settings_response import FeedGetSettingsResponse as FeedGetSettingsResponse 11 | from .guide_get_channel_response import GuideGetChannelResponse as GuideGetChannelResponse 12 | from .bulk_set_preferences_params import BulkSetPreferencesParams as BulkSetPreferencesParams 13 | from .guide_mark_message_as_seen_params import GuideMarkMessageAsSeenParams as GuideMarkMessageAsSeenParams 14 | from .guide_mark_message_as_seen_response import GuideMarkMessageAsSeenResponse as GuideMarkMessageAsSeenResponse 15 | from .guide_mark_message_as_archived_params import GuideMarkMessageAsArchivedParams as GuideMarkMessageAsArchivedParams 16 | from .guide_mark_message_as_archived_response import ( 17 | GuideMarkMessageAsArchivedResponse as GuideMarkMessageAsArchivedResponse, 18 | ) 19 | from .guide_mark_message_as_interacted_params import ( 20 | GuideMarkMessageAsInteractedParams as GuideMarkMessageAsInteractedParams, 21 | ) 22 | from .guide_mark_message_as_interacted_response import ( 23 | GuideMarkMessageAsInteractedResponse as GuideMarkMessageAsInteractedResponse, 24 | ) 25 | -------------------------------------------------------------------------------- /src/knockapi/types/users/feed_list_items_params.py: -------------------------------------------------------------------------------- 1 | # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | from __future__ import annotations 4 | 5 | from typing_extensions import Literal, TypedDict 6 | 7 | from ..._types import SequenceNotStr 8 | 9 | __all__ = ["FeedListItemsParams"] 10 | 11 | 12 | class FeedListItemsParams(TypedDict, total=False): 13 | after: str 14 | """The cursor to fetch entries after.""" 15 | 16 | archived: Literal["exclude", "include", "only"] 17 | """The archived status of the feed items.""" 18 | 19 | before: str 20 | """The cursor to fetch entries before.""" 21 | 22 | has_tenant: bool 23 | """Whether the feed items have a tenant.""" 24 | 25 | locale: str 26 | """The locale to render the feed items in. 27 | 28 | Must be in the IETF 5646 format (e.g. `en-US`). When not provided, will default 29 | to the locale that the feed items were rendered in. Only available for 30 | enterprise plan customers using custom translations. 31 | """ 32 | 33 | page_size: int 34 | """The number of items per page (defaults to 50).""" 35 | 36 | source: str 37 | """The workflow key associated with the message in the feed.""" 38 | 39 | status: Literal["unread", "read", "unseen", "seen", "all"] 40 | """The status of the feed items.""" 41 | 42 | tenant: str 43 | """The tenant associated with the feed items.""" 44 | 45 | trigger_data: str 46 | """The trigger data of the feed items (as a JSON string).""" 47 | 48 | workflow_categories: SequenceNotStr[str] 49 | """The workflow categories of the feed items.""" 50 | -------------------------------------------------------------------------------- /src/knockapi/types/messages/__init__.py: -------------------------------------------------------------------------------- 1 | # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | from __future__ import annotations 4 | 5 | from .batch_archive_params import BatchArchiveParams as BatchArchiveParams 6 | from .batch_archive_response import BatchArchiveResponse as BatchArchiveResponse 7 | from .batch_unarchive_params import BatchUnarchiveParams as BatchUnarchiveParams 8 | from .batch_get_content_params import BatchGetContentParams as BatchGetContentParams 9 | from .batch_unarchive_response import BatchUnarchiveResponse as BatchUnarchiveResponse 10 | from .batch_mark_as_read_params import BatchMarkAsReadParams as BatchMarkAsReadParams 11 | from .batch_mark_as_seen_params import BatchMarkAsSeenParams as BatchMarkAsSeenParams 12 | from .batch_get_content_response import BatchGetContentResponse as BatchGetContentResponse 13 | from .batch_mark_as_read_response import BatchMarkAsReadResponse as BatchMarkAsReadResponse 14 | from .batch_mark_as_seen_response import BatchMarkAsSeenResponse as BatchMarkAsSeenResponse 15 | from .batch_mark_as_unread_params import BatchMarkAsUnreadParams as BatchMarkAsUnreadParams 16 | from .batch_mark_as_unseen_params import BatchMarkAsUnseenParams as BatchMarkAsUnseenParams 17 | from .batch_mark_as_unread_response import BatchMarkAsUnreadResponse as BatchMarkAsUnreadResponse 18 | from .batch_mark_as_unseen_response import BatchMarkAsUnseenResponse as BatchMarkAsUnseenResponse 19 | from .batch_mark_as_interacted_params import BatchMarkAsInteractedParams as BatchMarkAsInteractedParams 20 | from .batch_mark_as_interacted_response import BatchMarkAsInteractedResponse as BatchMarkAsInteractedResponse 21 | -------------------------------------------------------------------------------- /src/knockapi/types/recipients/ms_teams_channel_data.py: -------------------------------------------------------------------------------- 1 | # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | from typing import List, Union, Optional 4 | from typing_extensions import TypeAlias 5 | 6 | from ..._models import BaseModel 7 | 8 | __all__ = [ 9 | "MsTeamsChannelData", 10 | "Connection", 11 | "ConnectionMsTeamsTokenConnection", 12 | "ConnectionMsTeamsIncomingWebhookConnection", 13 | "ConnectionMsTeamsIncomingWebhookConnectionIncomingWebhook", 14 | ] 15 | 16 | 17 | class ConnectionMsTeamsTokenConnection(BaseModel): 18 | ms_teams_channel_id: Optional[str] = None 19 | """Microsoft Teams channel ID.""" 20 | 21 | ms_teams_team_id: Optional[str] = None 22 | """Microsoft Teams team ID.""" 23 | 24 | ms_teams_tenant_id: Optional[str] = None 25 | """Microsoft Teams tenant ID.""" 26 | 27 | ms_teams_user_id: Optional[str] = None 28 | """Microsoft Teams user ID.""" 29 | 30 | 31 | class ConnectionMsTeamsIncomingWebhookConnectionIncomingWebhook(BaseModel): 32 | url: str 33 | """Microsoft Teams incoming webhook URL.""" 34 | 35 | 36 | class ConnectionMsTeamsIncomingWebhookConnection(BaseModel): 37 | incoming_webhook: ConnectionMsTeamsIncomingWebhookConnectionIncomingWebhook 38 | """Microsoft Teams incoming webhook.""" 39 | 40 | 41 | Connection: TypeAlias = Union[ConnectionMsTeamsTokenConnection, ConnectionMsTeamsIncomingWebhookConnection] 42 | 43 | 44 | class MsTeamsChannelData(BaseModel): 45 | connections: List[Connection] 46 | """List of Microsoft Teams connections.""" 47 | 48 | ms_teams_tenant_id: Optional[str] = None 49 | """Microsoft Teams tenant ID.""" 50 | -------------------------------------------------------------------------------- /src/knockapi/resources/providers/__init__.py: -------------------------------------------------------------------------------- 1 | # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | from .slack import ( 4 | SlackResource, 5 | AsyncSlackResource, 6 | SlackResourceWithRawResponse, 7 | AsyncSlackResourceWithRawResponse, 8 | SlackResourceWithStreamingResponse, 9 | AsyncSlackResourceWithStreamingResponse, 10 | ) 11 | from .ms_teams import ( 12 | MsTeamsResource, 13 | AsyncMsTeamsResource, 14 | MsTeamsResourceWithRawResponse, 15 | AsyncMsTeamsResourceWithRawResponse, 16 | MsTeamsResourceWithStreamingResponse, 17 | AsyncMsTeamsResourceWithStreamingResponse, 18 | ) 19 | from .providers import ( 20 | ProvidersResource, 21 | AsyncProvidersResource, 22 | ProvidersResourceWithRawResponse, 23 | AsyncProvidersResourceWithRawResponse, 24 | ProvidersResourceWithStreamingResponse, 25 | AsyncProvidersResourceWithStreamingResponse, 26 | ) 27 | 28 | __all__ = [ 29 | "SlackResource", 30 | "AsyncSlackResource", 31 | "SlackResourceWithRawResponse", 32 | "AsyncSlackResourceWithRawResponse", 33 | "SlackResourceWithStreamingResponse", 34 | "AsyncSlackResourceWithStreamingResponse", 35 | "MsTeamsResource", 36 | "AsyncMsTeamsResource", 37 | "MsTeamsResourceWithRawResponse", 38 | "AsyncMsTeamsResourceWithRawResponse", 39 | "MsTeamsResourceWithStreamingResponse", 40 | "AsyncMsTeamsResourceWithStreamingResponse", 41 | "ProvidersResource", 42 | "AsyncProvidersResource", 43 | "ProvidersResourceWithRawResponse", 44 | "AsyncProvidersResourceWithRawResponse", 45 | "ProvidersResourceWithStreamingResponse", 46 | "AsyncProvidersResourceWithStreamingResponse", 47 | ] 48 | -------------------------------------------------------------------------------- /scripts/test: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | 5 | cd "$(dirname "$0")/.." 6 | 7 | RED='\033[0;31m' 8 | GREEN='\033[0;32m' 9 | YELLOW='\033[0;33m' 10 | NC='\033[0m' # No Color 11 | 12 | function prism_is_running() { 13 | curl --silent "http://localhost:4010" >/dev/null 2>&1 14 | } 15 | 16 | kill_server_on_port() { 17 | pids=$(lsof -t -i tcp:"$1" || echo "") 18 | if [ "$pids" != "" ]; then 19 | kill "$pids" 20 | echo "Stopped $pids." 21 | fi 22 | } 23 | 24 | function is_overriding_api_base_url() { 25 | [ -n "$TEST_API_BASE_URL" ] 26 | } 27 | 28 | if ! is_overriding_api_base_url && ! prism_is_running ; then 29 | # When we exit this script, make sure to kill the background mock server process 30 | trap 'kill_server_on_port 4010' EXIT 31 | 32 | # Start the dev server 33 | ./scripts/mock --daemon 34 | fi 35 | 36 | if is_overriding_api_base_url ; then 37 | echo -e "${GREEN}✔ Running tests against ${TEST_API_BASE_URL}${NC}" 38 | echo 39 | elif ! prism_is_running ; then 40 | echo -e "${RED}ERROR:${NC} The test suite will not run without a mock Prism server" 41 | echo -e "running against your OpenAPI spec." 42 | echo 43 | echo -e "To run the server, pass in the path or url of your OpenAPI" 44 | echo -e "spec to the prism command:" 45 | echo 46 | echo -e " \$ ${YELLOW}npm exec --package=@stainless-api/prism-cli@5.15.0 -- prism mock path/to/your.openapi.yml${NC}" 47 | echo 48 | 49 | exit 1 50 | else 51 | echo -e "${GREEN}✔ Mock prism server is running with your OpenAPI spec${NC}" 52 | echo 53 | fi 54 | 55 | export DEFER_PYDANTIC_BUILD=false 56 | 57 | echo "==> Running tests" 58 | rye run pytest "$@" 59 | 60 | echo "==> Running Pydantic v1 tests" 61 | rye run nox -s test-pydantic-v1 -- "$@" 62 | -------------------------------------------------------------------------------- /requirements.lock: -------------------------------------------------------------------------------- 1 | # generated by rye 2 | # use `rye lock` or `rye sync` to update this lockfile 3 | # 4 | # last locked with the following flags: 5 | # pre: false 6 | # features: [] 7 | # all-features: true 8 | # with-sources: false 9 | # generate-hashes: false 10 | # universal: false 11 | 12 | -e file:. 13 | aiohappyeyeballs==2.6.1 14 | # via aiohttp 15 | aiohttp==3.12.8 16 | # via httpx-aiohttp 17 | # via knockapi 18 | aiosignal==1.3.2 19 | # via aiohttp 20 | annotated-types==0.6.0 21 | # via pydantic 22 | anyio==4.4.0 23 | # via httpx 24 | # via knockapi 25 | async-timeout==5.0.1 26 | # via aiohttp 27 | attrs==25.3.0 28 | # via aiohttp 29 | certifi==2023.7.22 30 | # via httpcore 31 | # via httpx 32 | distro==1.8.0 33 | # via knockapi 34 | exceptiongroup==1.2.2 35 | # via anyio 36 | frozenlist==1.6.2 37 | # via aiohttp 38 | # via aiosignal 39 | h11==0.16.0 40 | # via httpcore 41 | httpcore==1.0.9 42 | # via httpx 43 | httpx==0.28.1 44 | # via httpx-aiohttp 45 | # via knockapi 46 | httpx-aiohttp==0.1.9 47 | # via knockapi 48 | idna==3.4 49 | # via anyio 50 | # via httpx 51 | # via yarl 52 | multidict==6.4.4 53 | # via aiohttp 54 | # via yarl 55 | propcache==0.3.1 56 | # via aiohttp 57 | # via yarl 58 | pydantic==2.11.9 59 | # via knockapi 60 | pydantic-core==2.33.2 61 | # via pydantic 62 | sniffio==1.3.0 63 | # via anyio 64 | # via knockapi 65 | typing-extensions==4.12.2 66 | # via anyio 67 | # via knockapi 68 | # via multidict 69 | # via pydantic 70 | # via pydantic-core 71 | # via typing-inspection 72 | typing-inspection==0.4.1 73 | # via pydantic 74 | yarl==1.20.0 75 | # via aiohttp 76 | -------------------------------------------------------------------------------- /src/knockapi/types/recipients/ms_teams_channel_data_param.py: -------------------------------------------------------------------------------- 1 | # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | from __future__ import annotations 4 | 5 | from typing import Union, Iterable, Optional 6 | from typing_extensions import Required, TypeAlias, TypedDict 7 | 8 | __all__ = [ 9 | "MsTeamsChannelDataParam", 10 | "Connection", 11 | "ConnectionMsTeamsTokenConnection", 12 | "ConnectionMsTeamsIncomingWebhookConnection", 13 | "ConnectionMsTeamsIncomingWebhookConnectionIncomingWebhook", 14 | ] 15 | 16 | 17 | class ConnectionMsTeamsTokenConnection(TypedDict, total=False): 18 | ms_teams_channel_id: Optional[str] 19 | """Microsoft Teams channel ID.""" 20 | 21 | ms_teams_team_id: Optional[str] 22 | """Microsoft Teams team ID.""" 23 | 24 | ms_teams_tenant_id: Optional[str] 25 | """Microsoft Teams tenant ID.""" 26 | 27 | ms_teams_user_id: Optional[str] 28 | """Microsoft Teams user ID.""" 29 | 30 | 31 | class ConnectionMsTeamsIncomingWebhookConnectionIncomingWebhook(TypedDict, total=False): 32 | url: Required[str] 33 | """Microsoft Teams incoming webhook URL.""" 34 | 35 | 36 | class ConnectionMsTeamsIncomingWebhookConnection(TypedDict, total=False): 37 | incoming_webhook: Required[ConnectionMsTeamsIncomingWebhookConnectionIncomingWebhook] 38 | """Microsoft Teams incoming webhook.""" 39 | 40 | 41 | Connection: TypeAlias = Union[ConnectionMsTeamsTokenConnection, ConnectionMsTeamsIncomingWebhookConnection] 42 | 43 | 44 | class MsTeamsChannelDataParam(TypedDict, total=False): 45 | connections: Required[Iterable[Connection]] 46 | """List of Microsoft Teams connections.""" 47 | 48 | ms_teams_tenant_id: Optional[str] 49 | """Microsoft Teams tenant ID.""" 50 | -------------------------------------------------------------------------------- /src/knockapi/resources/integrations/__init__.py: -------------------------------------------------------------------------------- 1 | # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | from .census import ( 4 | CensusResource, 5 | AsyncCensusResource, 6 | CensusResourceWithRawResponse, 7 | AsyncCensusResourceWithRawResponse, 8 | CensusResourceWithStreamingResponse, 9 | AsyncCensusResourceWithStreamingResponse, 10 | ) 11 | from .hightouch import ( 12 | HightouchResource, 13 | AsyncHightouchResource, 14 | HightouchResourceWithRawResponse, 15 | AsyncHightouchResourceWithRawResponse, 16 | HightouchResourceWithStreamingResponse, 17 | AsyncHightouchResourceWithStreamingResponse, 18 | ) 19 | from .integrations import ( 20 | IntegrationsResource, 21 | AsyncIntegrationsResource, 22 | IntegrationsResourceWithRawResponse, 23 | AsyncIntegrationsResourceWithRawResponse, 24 | IntegrationsResourceWithStreamingResponse, 25 | AsyncIntegrationsResourceWithStreamingResponse, 26 | ) 27 | 28 | __all__ = [ 29 | "CensusResource", 30 | "AsyncCensusResource", 31 | "CensusResourceWithRawResponse", 32 | "AsyncCensusResourceWithRawResponse", 33 | "CensusResourceWithStreamingResponse", 34 | "AsyncCensusResourceWithStreamingResponse", 35 | "HightouchResource", 36 | "AsyncHightouchResource", 37 | "HightouchResourceWithRawResponse", 38 | "AsyncHightouchResourceWithRawResponse", 39 | "HightouchResourceWithStreamingResponse", 40 | "AsyncHightouchResourceWithStreamingResponse", 41 | "IntegrationsResource", 42 | "AsyncIntegrationsResource", 43 | "IntegrationsResourceWithRawResponse", 44 | "AsyncIntegrationsResourceWithRawResponse", 45 | "IntegrationsResourceWithStreamingResponse", 46 | "AsyncIntegrationsResourceWithStreamingResponse", 47 | ] 48 | -------------------------------------------------------------------------------- /tests/test_files.py: -------------------------------------------------------------------------------- 1 | from pathlib import Path 2 | 3 | import anyio 4 | import pytest 5 | from dirty_equals import IsDict, IsList, IsBytes, IsTuple 6 | 7 | from knockapi._files import to_httpx_files, async_to_httpx_files 8 | 9 | readme_path = Path(__file__).parent.parent.joinpath("README.md") 10 | 11 | 12 | def test_pathlib_includes_file_name() -> None: 13 | result = to_httpx_files({"file": readme_path}) 14 | print(result) 15 | assert result == IsDict({"file": IsTuple("README.md", IsBytes())}) 16 | 17 | 18 | def test_tuple_input() -> None: 19 | result = to_httpx_files([("file", readme_path)]) 20 | print(result) 21 | assert result == IsList(IsTuple("file", IsTuple("README.md", IsBytes()))) 22 | 23 | 24 | @pytest.mark.asyncio 25 | async def test_async_pathlib_includes_file_name() -> None: 26 | result = await async_to_httpx_files({"file": readme_path}) 27 | print(result) 28 | assert result == IsDict({"file": IsTuple("README.md", IsBytes())}) 29 | 30 | 31 | @pytest.mark.asyncio 32 | async def test_async_supports_anyio_path() -> None: 33 | result = await async_to_httpx_files({"file": anyio.Path(readme_path)}) 34 | print(result) 35 | assert result == IsDict({"file": IsTuple("README.md", IsBytes())}) 36 | 37 | 38 | @pytest.mark.asyncio 39 | async def test_async_tuple_input() -> None: 40 | result = await async_to_httpx_files([("file", readme_path)]) 41 | print(result) 42 | assert result == IsList(IsTuple("file", IsTuple("README.md", IsBytes()))) 43 | 44 | 45 | def test_string_not_allowed() -> None: 46 | with pytest.raises(TypeError, match="Expected file types input to be a FileContent type or to be a tuple"): 47 | to_httpx_files( 48 | { 49 | "file": "foo", # type: ignore 50 | } 51 | ) 52 | -------------------------------------------------------------------------------- /tests/test_deepcopy.py: -------------------------------------------------------------------------------- 1 | from knockapi._utils import deepcopy_minimal 2 | 3 | 4 | def assert_different_identities(obj1: object, obj2: object) -> None: 5 | assert obj1 == obj2 6 | assert id(obj1) != id(obj2) 7 | 8 | 9 | def test_simple_dict() -> None: 10 | obj1 = {"foo": "bar"} 11 | obj2 = deepcopy_minimal(obj1) 12 | assert_different_identities(obj1, obj2) 13 | 14 | 15 | def test_nested_dict() -> None: 16 | obj1 = {"foo": {"bar": True}} 17 | obj2 = deepcopy_minimal(obj1) 18 | assert_different_identities(obj1, obj2) 19 | assert_different_identities(obj1["foo"], obj2["foo"]) 20 | 21 | 22 | def test_complex_nested_dict() -> None: 23 | obj1 = {"foo": {"bar": [{"hello": "world"}]}} 24 | obj2 = deepcopy_minimal(obj1) 25 | assert_different_identities(obj1, obj2) 26 | assert_different_identities(obj1["foo"], obj2["foo"]) 27 | assert_different_identities(obj1["foo"]["bar"], obj2["foo"]["bar"]) 28 | assert_different_identities(obj1["foo"]["bar"][0], obj2["foo"]["bar"][0]) 29 | 30 | 31 | def test_simple_list() -> None: 32 | obj1 = ["a", "b", "c"] 33 | obj2 = deepcopy_minimal(obj1) 34 | assert_different_identities(obj1, obj2) 35 | 36 | 37 | def test_nested_list() -> None: 38 | obj1 = ["a", [1, 2, 3]] 39 | obj2 = deepcopy_minimal(obj1) 40 | assert_different_identities(obj1, obj2) 41 | assert_different_identities(obj1[1], obj2[1]) 42 | 43 | 44 | class MyObject: ... 45 | 46 | 47 | def test_ignores_other_types() -> None: 48 | # custom classes 49 | my_obj = MyObject() 50 | obj1 = {"foo": my_obj} 51 | obj2 = deepcopy_minimal(obj1) 52 | assert_different_identities(obj1, obj2) 53 | assert obj1["foo"] is my_obj 54 | 55 | # tuples 56 | obj3 = ("a", "b") 57 | obj4 = deepcopy_minimal(obj3) 58 | assert obj3 is obj4 59 | -------------------------------------------------------------------------------- /src/knockapi/_utils/_sync.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | import asyncio 4 | import functools 5 | from typing import TypeVar, Callable, Awaitable 6 | from typing_extensions import ParamSpec 7 | 8 | import anyio 9 | import sniffio 10 | import anyio.to_thread 11 | 12 | T_Retval = TypeVar("T_Retval") 13 | T_ParamSpec = ParamSpec("T_ParamSpec") 14 | 15 | 16 | async def to_thread( 17 | func: Callable[T_ParamSpec, T_Retval], /, *args: T_ParamSpec.args, **kwargs: T_ParamSpec.kwargs 18 | ) -> T_Retval: 19 | if sniffio.current_async_library() == "asyncio": 20 | return await asyncio.to_thread(func, *args, **kwargs) 21 | 22 | return await anyio.to_thread.run_sync( 23 | functools.partial(func, *args, **kwargs), 24 | ) 25 | 26 | 27 | # inspired by `asyncer`, https://github.com/tiangolo/asyncer 28 | def asyncify(function: Callable[T_ParamSpec, T_Retval]) -> Callable[T_ParamSpec, Awaitable[T_Retval]]: 29 | """ 30 | Take a blocking function and create an async one that receives the same 31 | positional and keyword arguments. 32 | 33 | Usage: 34 | 35 | ```python 36 | def blocking_func(arg1, arg2, kwarg1=None): 37 | # blocking code 38 | return result 39 | 40 | 41 | result = asyncify(blocking_function)(arg1, arg2, kwarg1=value1) 42 | ``` 43 | 44 | ## Arguments 45 | 46 | `function`: a blocking regular callable (e.g. a function) 47 | 48 | ## Return 49 | 50 | An async function that takes the same positional and keyword arguments as the 51 | original one, that when called runs the same original function in a thread worker 52 | and returns the result. 53 | """ 54 | 55 | async def wrapper(*args: T_ParamSpec.args, **kwargs: T_ParamSpec.kwargs) -> T_Retval: 56 | return await to_thread(function, *args, **kwargs) 57 | 58 | return wrapper 59 | -------------------------------------------------------------------------------- /src/knockapi/types/schedule_update_params.py: -------------------------------------------------------------------------------- 1 | # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | from __future__ import annotations 4 | 5 | from typing import Dict, Union, Iterable, Optional 6 | from datetime import datetime 7 | from typing_extensions import Required, Annotated, TypedDict 8 | 9 | from .._types import SequenceNotStr 10 | from .._utils import PropertyInfo 11 | from .recipient_reference_param import RecipientReferenceParam 12 | from .schedule_repeat_rule_param import ScheduleRepeatRuleParam 13 | from .inline_tenant_request_param import InlineTenantRequestParam 14 | 15 | __all__ = ["ScheduleUpdateParams"] 16 | 17 | 18 | class ScheduleUpdateParams(TypedDict, total=False): 19 | schedule_ids: Required[SequenceNotStr[str]] 20 | """A list of schedule IDs.""" 21 | 22 | actor: Optional[RecipientReferenceParam] 23 | """ 24 | A reference to a recipient, either a user identifier (string) or an object 25 | reference (ID, collection). 26 | """ 27 | 28 | data: Optional[Dict[str, object]] 29 | """An optional map of data to pass into the workflow execution. 30 | 31 | There is a 10MB limit on the size of the full `data` payload. Any individual 32 | string value greater than 1024 bytes in length will be 33 | [truncated](/developer-tools/api-logs#log-truncation) in your logs. 34 | """ 35 | 36 | ending_at: Annotated[Union[str, datetime, None], PropertyInfo(format="iso8601")] 37 | """The ending date and time for the schedule.""" 38 | 39 | repeats: Iterable[ScheduleRepeatRuleParam] 40 | """The repeat rule for the schedule.""" 41 | 42 | scheduled_at: Annotated[Union[str, datetime, None], PropertyInfo(format="iso8601")] 43 | """The starting date and time for the schedule.""" 44 | 45 | tenant: Optional[InlineTenantRequestParam] 46 | """An request to set a tenant inline.""" 47 | -------------------------------------------------------------------------------- /src/knockapi/types/tenant_set_params.py: -------------------------------------------------------------------------------- 1 | # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | from __future__ import annotations 4 | 5 | from typing import Optional 6 | from typing_extensions import TypedDict 7 | 8 | from .recipients.preference_set_request_param import PreferenceSetRequestParam 9 | from .recipients.inline_channel_data_request_param import InlineChannelDataRequestParam 10 | 11 | __all__ = ["TenantSetParams", "Settings", "SettingsBranding"] 12 | 13 | 14 | class TenantSetParams(TypedDict, total=False): 15 | resolve_full_preference_settings: bool 16 | """ 17 | When true, merges environment-level default preferences into the tenant's 18 | `settings.preference_set` field before returning the response. Defaults to 19 | false. 20 | """ 21 | 22 | channel_data: Optional[InlineChannelDataRequestParam] 23 | """A request to set channel data for a type of channel inline.""" 24 | 25 | name: Optional[str] 26 | """An optional name for the tenant.""" 27 | 28 | settings: Settings 29 | """The settings for the tenant. Includes branding and preference set.""" 30 | 31 | 32 | class SettingsBranding(TypedDict, total=False): 33 | icon_url: Optional[str] 34 | """The icon URL for the tenant. 35 | 36 | Must point to a valid image with an image MIME type. 37 | """ 38 | 39 | logo_url: Optional[str] 40 | """The logo URL for the tenant. 41 | 42 | Must point to a valid image with an image MIME type. 43 | """ 44 | 45 | primary_color: Optional[str] 46 | """The primary color for the tenant, provided as a hex value.""" 47 | 48 | primary_color_contrast: Optional[str] 49 | """The primary color contrast for the tenant, provided as a hex value.""" 50 | 51 | 52 | class Settings(TypedDict, total=False): 53 | branding: SettingsBranding 54 | """The branding for the tenant.""" 55 | 56 | preference_set: Optional[PreferenceSetRequestParam] 57 | """A request to set a preference set for a recipient.""" 58 | -------------------------------------------------------------------------------- /src/knockapi/types/workflow_trigger_params.py: -------------------------------------------------------------------------------- 1 | # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | from __future__ import annotations 4 | 5 | from typing import Dict, Optional 6 | from typing_extensions import Required, TypedDict 7 | 8 | from .._types import SequenceNotStr 9 | from .recipient_request_param import RecipientRequestParam 10 | from .inline_tenant_request_param import InlineTenantRequestParam 11 | 12 | __all__ = ["WorkflowTriggerParams"] 13 | 14 | 15 | class WorkflowTriggerParams(TypedDict, total=False): 16 | recipients: Required[SequenceNotStr[RecipientRequestParam]] 17 | """The recipients to trigger the workflow for. 18 | 19 | Can inline identify users, objects, or use a list of user IDs. Limited to 1,000 20 | recipients. 21 | """ 22 | 23 | actor: Optional[RecipientRequestParam] 24 | """Specifies a recipient in a request. 25 | 26 | This can either be a user identifier (string), an inline user request (object), 27 | or an inline object request, which is determined by the presence of a 28 | `collection` property. 29 | """ 30 | 31 | cancellation_key: Optional[str] 32 | """ 33 | An optional key that is used to reference a specific workflow trigger request 34 | when issuing a [workflow cancellation](/send-notifications/canceling-workflows) 35 | request. Must be provided while triggering a workflow in order to enable 36 | subsequent cancellation. Should be unique across trigger requests to avoid 37 | unintentional cancellations. 38 | """ 39 | 40 | data: Optional[Dict[str, object]] 41 | """An optional map of data to pass into the workflow execution. 42 | 43 | There is a 10MB limit on the size of the full `data` payload. Any individual 44 | string value greater than 1024 bytes in length will be 45 | [truncated](/developer-tools/api-logs#log-truncation) in your logs. 46 | """ 47 | 48 | tenant: Optional[InlineTenantRequestParam] 49 | """An request to set a tenant inline.""" 50 | -------------------------------------------------------------------------------- /src/knockapi/types/bulk_operation.py: -------------------------------------------------------------------------------- 1 | # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | from typing import List, Optional 4 | from datetime import datetime 5 | from typing_extensions import Literal 6 | 7 | from pydantic import Field as FieldInfo 8 | 9 | from .._models import BaseModel 10 | 11 | __all__ = ["BulkOperation", "ErrorItem"] 12 | 13 | 14 | class ErrorItem(BaseModel): 15 | id: str 16 | """Unique identifier for the object.""" 17 | 18 | collection: Optional[str] = None 19 | """The collection this object belongs to.""" 20 | 21 | 22 | class BulkOperation(BaseModel): 23 | id: str 24 | """Unique identifier for the bulk operation.""" 25 | 26 | api_typename: str = FieldInfo(alias="__typename") 27 | """The typename of the schema.""" 28 | 29 | estimated_total_rows: int 30 | """The estimated total number of rows to process.""" 31 | 32 | inserted_at: datetime 33 | """Timestamp when the resource was created.""" 34 | 35 | name: str 36 | """The name of the bulk operation.""" 37 | 38 | processed_rows: int 39 | """The number of rows processed so far.""" 40 | 41 | status: Literal["queued", "processing", "completed", "failed"] 42 | """The status of the bulk operation.""" 43 | 44 | success_count: int 45 | """The number of successful operations.""" 46 | 47 | updated_at: datetime 48 | """The timestamp when the resource was last updated.""" 49 | 50 | completed_at: Optional[datetime] = None 51 | """Timestamp when the bulk operation was completed.""" 52 | 53 | error_count: Optional[int] = None 54 | """The number of failed operations.""" 55 | 56 | error_items: Optional[List[ErrorItem]] = None 57 | """A list of items that failed to be processed.""" 58 | 59 | failed_at: Optional[datetime] = None 60 | """Timestamp when the bulk operation failed.""" 61 | 62 | progress_path: Optional[str] = None 63 | """The URI to the bulk operation's progress.""" 64 | 65 | started_at: Optional[datetime] = None 66 | """Timestamp when the bulk operation was started.""" 67 | -------------------------------------------------------------------------------- /src/knockapi/resources/users/__init__.py: -------------------------------------------------------------------------------- 1 | # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | from .bulk import ( 4 | BulkResource, 5 | AsyncBulkResource, 6 | BulkResourceWithRawResponse, 7 | AsyncBulkResourceWithRawResponse, 8 | BulkResourceWithStreamingResponse, 9 | AsyncBulkResourceWithStreamingResponse, 10 | ) 11 | from .feeds import ( 12 | FeedsResource, 13 | AsyncFeedsResource, 14 | FeedsResourceWithRawResponse, 15 | AsyncFeedsResourceWithRawResponse, 16 | FeedsResourceWithStreamingResponse, 17 | AsyncFeedsResourceWithStreamingResponse, 18 | ) 19 | from .users import ( 20 | UsersResource, 21 | AsyncUsersResource, 22 | UsersResourceWithRawResponse, 23 | AsyncUsersResourceWithRawResponse, 24 | UsersResourceWithStreamingResponse, 25 | AsyncUsersResourceWithStreamingResponse, 26 | ) 27 | from .guides import ( 28 | GuidesResource, 29 | AsyncGuidesResource, 30 | GuidesResourceWithRawResponse, 31 | AsyncGuidesResourceWithRawResponse, 32 | GuidesResourceWithStreamingResponse, 33 | AsyncGuidesResourceWithStreamingResponse, 34 | ) 35 | 36 | __all__ = [ 37 | "FeedsResource", 38 | "AsyncFeedsResource", 39 | "FeedsResourceWithRawResponse", 40 | "AsyncFeedsResourceWithRawResponse", 41 | "FeedsResourceWithStreamingResponse", 42 | "AsyncFeedsResourceWithStreamingResponse", 43 | "GuidesResource", 44 | "AsyncGuidesResource", 45 | "GuidesResourceWithRawResponse", 46 | "AsyncGuidesResourceWithRawResponse", 47 | "GuidesResourceWithStreamingResponse", 48 | "AsyncGuidesResourceWithStreamingResponse", 49 | "BulkResource", 50 | "AsyncBulkResource", 51 | "BulkResourceWithRawResponse", 52 | "AsyncBulkResourceWithRawResponse", 53 | "BulkResourceWithStreamingResponse", 54 | "AsyncBulkResourceWithStreamingResponse", 55 | "UsersResource", 56 | "AsyncUsersResource", 57 | "UsersResourceWithRawResponse", 58 | "AsyncUsersResourceWithRawResponse", 59 | "UsersResourceWithStreamingResponse", 60 | "AsyncUsersResourceWithStreamingResponse", 61 | ] 62 | -------------------------------------------------------------------------------- /src/knockapi/types/channels/bulk_update_message_status_params.py: -------------------------------------------------------------------------------- 1 | # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | from __future__ import annotations 4 | 5 | from typing import Union 6 | from datetime import datetime 7 | from typing_extensions import Literal, Annotated, TypedDict 8 | 9 | from ..._types import SequenceNotStr 10 | from ..._utils import PropertyInfo 11 | 12 | __all__ = ["BulkUpdateMessageStatusParams"] 13 | 14 | 15 | class BulkUpdateMessageStatusParams(TypedDict, total=False): 16 | archived: Literal["exclude", "include", "only"] 17 | """Limits the results to messages with the given archived status.""" 18 | 19 | delivery_status: Literal["queued", "sent", "delivered", "delivery_attempted", "undelivered", "not_sent", "bounced"] 20 | """Limits the results to messages with the given delivery status.""" 21 | 22 | engagement_status: Literal[ 23 | "seen", "unseen", "read", "unread", "archived", "unarchived", "link_clicked", "interacted" 24 | ] 25 | """Limits the results to messages with the given engagement status.""" 26 | 27 | has_tenant: bool 28 | """Limits the results to messages that have a tenant or not.""" 29 | 30 | newer_than: Annotated[Union[str, datetime], PropertyInfo(format="iso8601")] 31 | """Limits the results to messages inserted after the given date.""" 32 | 33 | older_than: Annotated[Union[str, datetime], PropertyInfo(format="iso8601")] 34 | """Limits the results to messages inserted before the given date.""" 35 | 36 | recipient_ids: SequenceNotStr[str] 37 | """Limits the results to messages with the given recipient IDs.""" 38 | 39 | tenants: SequenceNotStr[str] 40 | """Limits the results to messages with the given tenant IDs.""" 41 | 42 | trigger_data: str 43 | """Limits the results to only messages that were generated with the given data. 44 | 45 | See [trigger data filtering](/api-reference/overview/trigger-data-filtering) for 46 | more information. 47 | """ 48 | 49 | workflows: SequenceNotStr[str] 50 | """Limits the results to messages with the given workflow keys.""" 51 | -------------------------------------------------------------------------------- /src/knockapi/types/schedule_create_params.py: -------------------------------------------------------------------------------- 1 | # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | from __future__ import annotations 4 | 5 | from typing import Dict, Union, Iterable, Optional 6 | from datetime import datetime 7 | from typing_extensions import Required, Annotated, TypedDict 8 | 9 | from .._types import SequenceNotStr 10 | from .._utils import PropertyInfo 11 | from .recipient_request_param import RecipientRequestParam 12 | from .schedule_repeat_rule_param import ScheduleRepeatRuleParam 13 | from .inline_tenant_request_param import InlineTenantRequestParam 14 | 15 | __all__ = ["ScheduleCreateParams"] 16 | 17 | 18 | class ScheduleCreateParams(TypedDict, total=False): 19 | recipients: Required[SequenceNotStr[RecipientRequestParam]] 20 | """The recipients to set the schedule for. Limited to 100 recipients per request.""" 21 | 22 | workflow: Required[str] 23 | """The key of the workflow.""" 24 | 25 | actor: Optional[RecipientRequestParam] 26 | """Specifies a recipient in a request. 27 | 28 | This can either be a user identifier (string), an inline user request (object), 29 | or an inline object request, which is determined by the presence of a 30 | `collection` property. 31 | """ 32 | 33 | data: Optional[Dict[str, object]] 34 | """An optional map of data to pass into the workflow execution. 35 | 36 | There is a 10MB limit on the size of the full `data` payload. Any individual 37 | string value greater than 1024 bytes in length will be 38 | [truncated](/developer-tools/api-logs#log-truncation) in your logs. 39 | """ 40 | 41 | ending_at: Annotated[Union[str, datetime, None], PropertyInfo(format="iso8601")] 42 | """The ending date and time for the schedule.""" 43 | 44 | repeats: Iterable[ScheduleRepeatRuleParam] 45 | """The repeat rule for the schedule.""" 46 | 47 | scheduled_at: Annotated[Union[str, datetime, None], PropertyInfo(format="iso8601")] 48 | """The starting date and time for the schedule.""" 49 | 50 | tenant: Optional[InlineTenantRequestParam] 51 | """An request to set a tenant inline.""" 52 | -------------------------------------------------------------------------------- /src/knockapi/types/schedule.py: -------------------------------------------------------------------------------- 1 | # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | from typing import Dict, List, Optional 4 | from datetime import datetime 5 | 6 | from pydantic import Field as FieldInfo 7 | 8 | from .._models import BaseModel 9 | from .recipient import Recipient 10 | from .schedule_repeat_rule import ScheduleRepeatRule 11 | 12 | __all__ = ["Schedule"] 13 | 14 | 15 | class Schedule(BaseModel): 16 | id: str 17 | """Unique identifier for the schedule.""" 18 | 19 | inserted_at: datetime 20 | """Timestamp when the resource was created.""" 21 | 22 | recipient: Recipient 23 | """A recipient of a notification, which is either a user or an object.""" 24 | 25 | repeats: List[ScheduleRepeatRule] 26 | """The repeat rule for the schedule.""" 27 | 28 | updated_at: datetime 29 | """The timestamp when the resource was last updated.""" 30 | 31 | workflow: str 32 | """The workflow the schedule is applied to.""" 33 | 34 | api_typename: Optional[str] = FieldInfo(alias="__typename", default=None) 35 | """The typename of the schema.""" 36 | 37 | actor: Optional[Recipient] = None 38 | """A recipient of a notification, which is either a user or an object.""" 39 | 40 | data: Optional[Dict[str, object]] = None 41 | """An optional map of data to pass into the workflow execution. 42 | 43 | There is a 10MB limit on the size of the full `data` payload. Any individual 44 | string value greater than 1024 bytes in length will be 45 | [truncated](/developer-tools/api-logs#log-truncation) in your logs. 46 | """ 47 | 48 | last_occurrence_at: Optional[datetime] = None 49 | """The last occurrence of the schedule.""" 50 | 51 | next_occurrence_at: Optional[datetime] = None 52 | """The next occurrence of the schedule.""" 53 | 54 | tenant: Optional[str] = None 55 | """The tenant to trigger the workflow for. 56 | 57 | Triggering with a tenant will use any tenant-level overrides associated with the 58 | tenant object, and all messages produced from workflow runs will be tagged with 59 | the tenant. 60 | """ 61 | -------------------------------------------------------------------------------- /src/knockapi/types/user_update_params.py: -------------------------------------------------------------------------------- 1 | # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | from __future__ import annotations 4 | 5 | from typing import Union, Optional 6 | from datetime import datetime 7 | from typing_extensions import Annotated, TypedDict 8 | 9 | from .._utils import PropertyInfo 10 | from .recipients.inline_channel_data_request_param import InlineChannelDataRequestParam 11 | from .recipients.inline_preference_set_request_param import InlinePreferenceSetRequestParam 12 | 13 | __all__ = ["UserUpdateParams"] 14 | 15 | 16 | class UserUpdateParams(TypedDict, total=False): 17 | avatar: Optional[str] 18 | """A URL for the avatar of the user.""" 19 | 20 | channel_data: Optional[InlineChannelDataRequestParam] 21 | """A request to set channel data for a type of channel inline.""" 22 | 23 | created_at: Annotated[Union[str, datetime, None], PropertyInfo(format="iso8601")] 24 | """The creation date of the user from your system.""" 25 | 26 | email: Optional[str] 27 | """The primary email address for the user.""" 28 | 29 | locale: Optional[str] 30 | """The locale of the user. 31 | 32 | Used for [message localization](/concepts/translations). 33 | """ 34 | 35 | name: Optional[str] 36 | """Display name of the user.""" 37 | 38 | phone_number: Optional[str] 39 | """ 40 | The [E.164](https://www.twilio.com/docs/glossary/what-e164) phone number of the 41 | user (required for SMS channels). 42 | """ 43 | 44 | preferences: Optional[InlinePreferenceSetRequestParam] 45 | """Inline set preferences for a recipient, where the key is the preference set id. 46 | 47 | Preferences that are set inline will be merged into any existing preferences 48 | rather than replacing them. 49 | """ 50 | 51 | timezone: Optional[str] 52 | """The timezone of the user. 53 | 54 | Must be a 55 | valid [tz database time zone string](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones). 56 | Used 57 | for [recurring schedules](/concepts/schedules#scheduling-workflows-with-recurring-schedules-for-recipients). 58 | """ 59 | -------------------------------------------------------------------------------- /src/knockapi/types/message_delivery_log.py: -------------------------------------------------------------------------------- 1 | # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | from typing import Dict, Union, Optional 4 | from typing_extensions import Literal 5 | 6 | from pydantic import Field as FieldInfo 7 | 8 | from .._models import BaseModel 9 | 10 | __all__ = ["MessageDeliveryLog", "Request", "Response"] 11 | 12 | 13 | class Request(BaseModel): 14 | body: Union[str, Dict[str, object], None] = None 15 | """The body content that was sent with the request.""" 16 | 17 | headers: Optional[Dict[str, object]] = None 18 | """The headers that were sent with the request.""" 19 | 20 | host: Optional[str] = None 21 | """The host to which the request was sent.""" 22 | 23 | method: Optional[Literal["GET", "POST", "PUT", "DELETE", "PATCH"]] = None 24 | """The HTTP method used for the request.""" 25 | 26 | path: Optional[str] = None 27 | """The path of the URL that was requested.""" 28 | 29 | query: Optional[str] = None 30 | """The query string of the URL that was requested.""" 31 | 32 | 33 | class Response(BaseModel): 34 | body: Union[str, Dict[str, object], None] = None 35 | """The body content that was received with the response.""" 36 | 37 | headers: Optional[Dict[str, object]] = None 38 | """The headers that were received with the response.""" 39 | 40 | status: Optional[int] = None 41 | """The HTTP status code of the response.""" 42 | 43 | 44 | class MessageDeliveryLog(BaseModel): 45 | id: str 46 | """The unique identifier for the message delivery log.""" 47 | 48 | api_typename: str = FieldInfo(alias="__typename") 49 | """The typename of the schema.""" 50 | 51 | environment_id: str 52 | """The ID of the environment in which the message delivery occurred.""" 53 | 54 | inserted_at: str 55 | """Timestamp when the message delivery log was created.""" 56 | 57 | request: Request 58 | """A message delivery log request.""" 59 | 60 | response: Response 61 | """A message delivery log response.""" 62 | 63 | service_name: str 64 | """The name of the service that processed the delivery.""" 65 | -------------------------------------------------------------------------------- /src/knockapi/types/user.py: -------------------------------------------------------------------------------- 1 | # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | from typing import TYPE_CHECKING, Dict, Optional 4 | from datetime import datetime 5 | 6 | from pydantic import Field as FieldInfo 7 | 8 | from .._models import BaseModel 9 | 10 | __all__ = ["User"] 11 | 12 | 13 | class User(BaseModel): 14 | id: str 15 | """The unique identifier of the user.""" 16 | 17 | api_typename: str = FieldInfo(alias="__typename") 18 | """The typename of the schema.""" 19 | 20 | updated_at: datetime 21 | """The timestamp when the resource was last updated.""" 22 | 23 | avatar: Optional[str] = None 24 | """A URL for the avatar of the user.""" 25 | 26 | created_at: Optional[datetime] = None 27 | """The creation date of the user from your system.""" 28 | 29 | email: Optional[str] = None 30 | """The primary email address for the user.""" 31 | 32 | name: Optional[str] = None 33 | """Display name of the user.""" 34 | 35 | phone_number: Optional[str] = None 36 | """ 37 | The [E.164](https://www.twilio.com/docs/glossary/what-e164) phone number of the 38 | user (required for SMS channels). 39 | """ 40 | 41 | timezone: Optional[str] = None 42 | """The timezone of the user. 43 | 44 | Must be a 45 | valid [tz database time zone string](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones). 46 | Used 47 | for [recurring schedules](/concepts/schedules#scheduling-workflows-with-recurring-schedules-for-recipients). 48 | """ 49 | 50 | if TYPE_CHECKING: 51 | # Some versions of Pydantic <2.8.0 have a bug and don’t allow assigning a 52 | # value to this field, so for compatibility we avoid doing it at runtime. 53 | __pydantic_extra__: Dict[str, object] = FieldInfo(init=False) # pyright: ignore[reportIncompatibleVariableOverride] 54 | 55 | # Stub to indicate that arbitrary properties are accepted. 56 | # To access properties that are not valid identifiers you can use `getattr`, e.g. 57 | # `getattr(obj, '$type')` 58 | def __getattr__(self, attr: str) -> object: ... 59 | else: 60 | __pydantic_extra__: Dict[str, object] 61 | -------------------------------------------------------------------------------- /tests/test_extract_files.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | from typing import Sequence 4 | 5 | import pytest 6 | 7 | from knockapi._types import FileTypes 8 | from knockapi._utils import extract_files 9 | 10 | 11 | def test_removes_files_from_input() -> None: 12 | query = {"foo": "bar"} 13 | assert extract_files(query, paths=[]) == [] 14 | assert query == {"foo": "bar"} 15 | 16 | query2 = {"foo": b"Bar", "hello": "world"} 17 | assert extract_files(query2, paths=[["foo"]]) == [("foo", b"Bar")] 18 | assert query2 == {"hello": "world"} 19 | 20 | query3 = {"foo": {"foo": {"bar": b"Bar"}}, "hello": "world"} 21 | assert extract_files(query3, paths=[["foo", "foo", "bar"]]) == [("foo[foo][bar]", b"Bar")] 22 | assert query3 == {"foo": {"foo": {}}, "hello": "world"} 23 | 24 | query4 = {"foo": {"bar": b"Bar", "baz": "foo"}, "hello": "world"} 25 | assert extract_files(query4, paths=[["foo", "bar"]]) == [("foo[bar]", b"Bar")] 26 | assert query4 == {"hello": "world", "foo": {"baz": "foo"}} 27 | 28 | 29 | def test_multiple_files() -> None: 30 | query = {"documents": [{"file": b"My first file"}, {"file": b"My second file"}]} 31 | assert extract_files(query, paths=[["documents", "", "file"]]) == [ 32 | ("documents[][file]", b"My first file"), 33 | ("documents[][file]", b"My second file"), 34 | ] 35 | assert query == {"documents": [{}, {}]} 36 | 37 | 38 | @pytest.mark.parametrize( 39 | "query,paths,expected", 40 | [ 41 | [ 42 | {"foo": {"bar": "baz"}}, 43 | [["foo", "", "bar"]], 44 | [], 45 | ], 46 | [ 47 | {"foo": ["bar", "baz"]}, 48 | [["foo", "bar"]], 49 | [], 50 | ], 51 | [ 52 | {"foo": {"bar": "baz"}}, 53 | [["foo", "foo"]], 54 | [], 55 | ], 56 | ], 57 | ids=["dict expecting array", "array expecting dict", "unknown keys"], 58 | ) 59 | def test_ignores_incorrect_paths( 60 | query: dict[str, object], 61 | paths: Sequence[Sequence[str]], 62 | expected: list[tuple[str, FileTypes]], 63 | ) -> None: 64 | assert extract_files(query, paths=paths) == expected 65 | -------------------------------------------------------------------------------- /src/knockapi/_utils/_proxy.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | from abc import ABC, abstractmethod 4 | from typing import Generic, TypeVar, Iterable, cast 5 | from typing_extensions import override 6 | 7 | T = TypeVar("T") 8 | 9 | 10 | class LazyProxy(Generic[T], ABC): 11 | """Implements data methods to pretend that an instance is another instance. 12 | 13 | This includes forwarding attribute access and other methods. 14 | """ 15 | 16 | # Note: we have to special case proxies that themselves return proxies 17 | # to support using a proxy as a catch-all for any random access, e.g. `proxy.foo.bar.baz` 18 | 19 | def __getattr__(self, attr: str) -> object: 20 | proxied = self.__get_proxied__() 21 | if isinstance(proxied, LazyProxy): 22 | return proxied # pyright: ignore 23 | return getattr(proxied, attr) 24 | 25 | @override 26 | def __repr__(self) -> str: 27 | proxied = self.__get_proxied__() 28 | if isinstance(proxied, LazyProxy): 29 | return proxied.__class__.__name__ 30 | return repr(self.__get_proxied__()) 31 | 32 | @override 33 | def __str__(self) -> str: 34 | proxied = self.__get_proxied__() 35 | if isinstance(proxied, LazyProxy): 36 | return proxied.__class__.__name__ 37 | return str(proxied) 38 | 39 | @override 40 | def __dir__(self) -> Iterable[str]: 41 | proxied = self.__get_proxied__() 42 | if isinstance(proxied, LazyProxy): 43 | return [] 44 | return proxied.__dir__() 45 | 46 | @property # type: ignore 47 | @override 48 | def __class__(self) -> type: # pyright: ignore 49 | try: 50 | proxied = self.__get_proxied__() 51 | except Exception: 52 | return type(self) 53 | if issubclass(type(proxied), LazyProxy): 54 | return type(proxied) 55 | return proxied.__class__ 56 | 57 | def __get_proxied__(self) -> T: 58 | return self.__load__() 59 | 60 | def __as_proxied__(self) -> T: 61 | """Helper method that returns the current proxy, typed as the loaded object""" 62 | return cast(T, self) 63 | 64 | @abstractmethod 65 | def __load__(self) -> T: ... 66 | -------------------------------------------------------------------------------- /src/knockapi/types/tenant_request_param.py: -------------------------------------------------------------------------------- 1 | # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | from __future__ import annotations 4 | 5 | from typing import Dict, Union, Optional 6 | from typing_extensions import Required, TypeAlias, TypedDict 7 | 8 | from .recipients.preference_set_request_param import PreferenceSetRequestParam 9 | from .recipients.inline_channel_data_request_param import InlineChannelDataRequestParam 10 | from .recipients.inline_preference_set_request_param import InlinePreferenceSetRequestParam 11 | 12 | __all__ = ["TenantRequestParam", "Settings", "SettingsBranding"] 13 | 14 | 15 | class SettingsBranding(TypedDict, total=False): 16 | icon_url: Optional[str] 17 | """The icon URL for the tenant. 18 | 19 | Must point to a valid image with an image MIME type. 20 | """ 21 | 22 | logo_url: Optional[str] 23 | """The logo URL for the tenant. 24 | 25 | Must point to a valid image with an image MIME type. 26 | """ 27 | 28 | primary_color: Optional[str] 29 | """The primary color for the tenant, provided as a hex value.""" 30 | 31 | primary_color_contrast: Optional[str] 32 | """The primary color contrast for the tenant, provided as a hex value.""" 33 | 34 | 35 | class Settings(TypedDict, total=False): 36 | branding: SettingsBranding 37 | """The branding for the tenant.""" 38 | 39 | preference_set: Optional[PreferenceSetRequestParam] 40 | """A request to set a preference set for a recipient.""" 41 | 42 | 43 | class TenantRequestParamTyped(TypedDict, total=False): 44 | id: Required[str] 45 | """The unique identifier for the tenant.""" 46 | 47 | channel_data: Optional[InlineChannelDataRequestParam] 48 | """A request to set channel data for a type of channel inline.""" 49 | 50 | name: Optional[str] 51 | """An optional name for the tenant.""" 52 | 53 | preferences: Optional[InlinePreferenceSetRequestParam] 54 | """Inline set preferences for a recipient, where the key is the preference set id. 55 | 56 | Preferences that are set inline will be merged into any existing preferences 57 | rather than replacing them. 58 | """ 59 | 60 | settings: Settings 61 | """The settings for the tenant. Includes branding and preference set.""" 62 | 63 | 64 | TenantRequestParam: TypeAlias = Union[TenantRequestParamTyped, Dict[str, object]] 65 | -------------------------------------------------------------------------------- /src/knockapi/types/schedules/bulk_create_params.py: -------------------------------------------------------------------------------- 1 | # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | from __future__ import annotations 4 | 5 | from typing import Dict, Union, Iterable, Optional 6 | from datetime import datetime 7 | from typing_extensions import Required, Annotated, TypedDict 8 | 9 | from ..._utils import PropertyInfo 10 | from ..recipient_request_param import RecipientRequestParam 11 | from ..schedule_repeat_rule_param import ScheduleRepeatRuleParam 12 | from ..inline_tenant_request_param import InlineTenantRequestParam 13 | 14 | __all__ = ["BulkCreateParams", "Schedule"] 15 | 16 | 17 | class BulkCreateParams(TypedDict, total=False): 18 | schedules: Required[Iterable[Schedule]] 19 | """A list of schedules.""" 20 | 21 | 22 | class Schedule(TypedDict, total=False): 23 | workflow: Required[str] 24 | """The key of the workflow.""" 25 | 26 | actor: Optional[RecipientRequestParam] 27 | """Specifies a recipient in a request. 28 | 29 | This can either be a user identifier (string), an inline user request (object), 30 | or an inline object request, which is determined by the presence of a 31 | `collection` property. 32 | """ 33 | 34 | data: Optional[Dict[str, object]] 35 | """An optional map of data to pass into the workflow execution. 36 | 37 | There is a 10MB limit on the size of the full `data` payload. Any individual 38 | string value greater than 1024 bytes in length will be 39 | [truncated](/developer-tools/api-logs#log-truncation) in your logs. 40 | """ 41 | 42 | ending_at: Annotated[Union[str, datetime, None], PropertyInfo(format="iso8601")] 43 | """The ending date and time for the schedule.""" 44 | 45 | recipient: RecipientRequestParam 46 | """Specifies a recipient in a request. 47 | 48 | This can either be a user identifier (string), an inline user request (object), 49 | or an inline object request, which is determined by the presence of a 50 | `collection` property. 51 | """ 52 | 53 | repeats: Iterable[ScheduleRepeatRuleParam] 54 | """The repeat rule for the schedule.""" 55 | 56 | scheduled_at: Annotated[Union[str, datetime, None], PropertyInfo(format="iso8601")] 57 | """The starting date and time for the schedule.""" 58 | 59 | tenant: Optional[InlineTenantRequestParam] 60 | """An request to set a tenant inline.""" 61 | -------------------------------------------------------------------------------- /src/knockapi/types/inline_identify_user_request_param.py: -------------------------------------------------------------------------------- 1 | # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | from __future__ import annotations 4 | 5 | from typing import Dict, Union, Optional 6 | from datetime import datetime 7 | from typing_extensions import Required, Annotated, TypeAlias, TypedDict 8 | 9 | from .._utils import PropertyInfo 10 | from .recipients.inline_channel_data_request_param import InlineChannelDataRequestParam 11 | from .recipients.inline_preference_set_request_param import InlinePreferenceSetRequestParam 12 | 13 | __all__ = ["InlineIdentifyUserRequestParam"] 14 | 15 | 16 | class InlineIdentifyUserRequestParamTyped(TypedDict, total=False): 17 | id: Required[str] 18 | """The unique identifier of the user.""" 19 | 20 | avatar: Optional[str] 21 | """A URL for the avatar of the user.""" 22 | 23 | channel_data: Optional[InlineChannelDataRequestParam] 24 | """A request to set channel data for a type of channel inline.""" 25 | 26 | created_at: Annotated[Union[str, datetime, None], PropertyInfo(format="iso8601")] 27 | """The creation date of the user from your system.""" 28 | 29 | email: Optional[str] 30 | """The primary email address for the user.""" 31 | 32 | locale: Optional[str] 33 | """The locale of the user. 34 | 35 | Used for [message localization](/concepts/translations). 36 | """ 37 | 38 | name: Optional[str] 39 | """Display name of the user.""" 40 | 41 | phone_number: Optional[str] 42 | """ 43 | The [E.164](https://www.twilio.com/docs/glossary/what-e164) phone number of the 44 | user (required for SMS channels). 45 | """ 46 | 47 | preferences: Optional[InlinePreferenceSetRequestParam] 48 | """Inline set preferences for a recipient, where the key is the preference set id. 49 | 50 | Preferences that are set inline will be merged into any existing preferences 51 | rather than replacing them. 52 | """ 53 | 54 | timezone: Optional[str] 55 | """The timezone of the user. 56 | 57 | Must be a 58 | valid [tz database time zone string](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones). 59 | Used 60 | for [recurring schedules](/concepts/schedules#scheduling-workflows-with-recurring-schedules-for-recipients). 61 | """ 62 | 63 | 64 | InlineIdentifyUserRequestParam: TypeAlias = Union[InlineIdentifyUserRequestParamTyped, Dict[str, object]] 65 | -------------------------------------------------------------------------------- /src/knockapi/types/tenant.py: -------------------------------------------------------------------------------- 1 | # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | from typing import TYPE_CHECKING, Dict, Optional 4 | 5 | from pydantic import Field as FieldInfo 6 | 7 | from .._models import BaseModel 8 | from .recipients.preference_set import PreferenceSet 9 | 10 | __all__ = ["Tenant", "Settings", "SettingsBranding"] 11 | 12 | 13 | class SettingsBranding(BaseModel): 14 | icon_url: Optional[str] = None 15 | """The icon URL for the tenant. 16 | 17 | Must point to a valid image with an image MIME type. 18 | """ 19 | 20 | logo_url: Optional[str] = None 21 | """The logo URL for the tenant. 22 | 23 | Must point to a valid image with an image MIME type. 24 | """ 25 | 26 | primary_color: Optional[str] = None 27 | """The primary color for the tenant, provided as a hex value.""" 28 | 29 | primary_color_contrast: Optional[str] = None 30 | """The primary color contrast for the tenant, provided as a hex value.""" 31 | 32 | 33 | class Settings(BaseModel): 34 | branding: Optional[SettingsBranding] = None 35 | """The branding for the tenant.""" 36 | 37 | preference_set: Optional[PreferenceSet] = None 38 | """ 39 | A preference set represents a specific set of notification preferences for a 40 | recipient. A recipient can have multiple preference sets. 41 | """ 42 | 43 | 44 | class Tenant(BaseModel): 45 | id: str 46 | """The unique identifier for the tenant.""" 47 | 48 | api_typename: str = FieldInfo(alias="__typename") 49 | """The typename of the schema.""" 50 | 51 | name: Optional[str] = None 52 | """An optional name for the tenant.""" 53 | 54 | settings: Optional[Settings] = None 55 | """The settings for the tenant. Includes branding and preference set.""" 56 | 57 | if TYPE_CHECKING: 58 | # Some versions of Pydantic <2.8.0 have a bug and don’t allow assigning a 59 | # value to this field, so for compatibility we avoid doing it at runtime. 60 | __pydantic_extra__: Dict[str, object] = FieldInfo(init=False) # pyright: ignore[reportIncompatibleVariableOverride] 61 | 62 | # Stub to indicate that arbitrary properties are accepted. 63 | # To access properties that are not valid identifiers you can use `getattr`, e.g. 64 | # `getattr(obj, '$type')` 65 | def __getattr__(self, attr: str) -> object: ... 66 | else: 67 | __pydantic_extra__: Dict[str, object] 68 | -------------------------------------------------------------------------------- /src/knockapi/_utils/__init__.py: -------------------------------------------------------------------------------- 1 | from ._sync import asyncify as asyncify 2 | from ._proxy import LazyProxy as LazyProxy 3 | from ._utils import ( 4 | flatten as flatten, 5 | is_dict as is_dict, 6 | is_list as is_list, 7 | is_given as is_given, 8 | is_tuple as is_tuple, 9 | json_safe as json_safe, 10 | lru_cache as lru_cache, 11 | is_mapping as is_mapping, 12 | is_tuple_t as is_tuple_t, 13 | is_iterable as is_iterable, 14 | is_sequence as is_sequence, 15 | coerce_float as coerce_float, 16 | is_mapping_t as is_mapping_t, 17 | removeprefix as removeprefix, 18 | removesuffix as removesuffix, 19 | extract_files as extract_files, 20 | is_sequence_t as is_sequence_t, 21 | required_args as required_args, 22 | coerce_boolean as coerce_boolean, 23 | coerce_integer as coerce_integer, 24 | file_from_path as file_from_path, 25 | strip_not_given as strip_not_given, 26 | deepcopy_minimal as deepcopy_minimal, 27 | get_async_library as get_async_library, 28 | maybe_coerce_float as maybe_coerce_float, 29 | get_required_header as get_required_header, 30 | maybe_coerce_boolean as maybe_coerce_boolean, 31 | maybe_coerce_integer as maybe_coerce_integer, 32 | ) 33 | from ._compat import ( 34 | get_args as get_args, 35 | is_union as is_union, 36 | get_origin as get_origin, 37 | is_typeddict as is_typeddict, 38 | is_literal_type as is_literal_type, 39 | ) 40 | from ._typing import ( 41 | is_list_type as is_list_type, 42 | is_union_type as is_union_type, 43 | extract_type_arg as extract_type_arg, 44 | is_iterable_type as is_iterable_type, 45 | is_required_type as is_required_type, 46 | is_sequence_type as is_sequence_type, 47 | is_annotated_type as is_annotated_type, 48 | is_type_alias_type as is_type_alias_type, 49 | strip_annotated_type as strip_annotated_type, 50 | extract_type_var_from_base as extract_type_var_from_base, 51 | ) 52 | from ._streams import consume_sync_iterator as consume_sync_iterator, consume_async_iterator as consume_async_iterator 53 | from ._transform import ( 54 | PropertyInfo as PropertyInfo, 55 | transform as transform, 56 | async_transform as async_transform, 57 | maybe_transform as maybe_transform, 58 | async_maybe_transform as async_maybe_transform, 59 | ) 60 | from ._reflection import ( 61 | function_has_argument as function_has_argument, 62 | assert_signatures_in_sync as assert_signatures_in_sync, 63 | ) 64 | from ._datetime_parse import parse_date as parse_date, parse_datetime as parse_datetime 65 | -------------------------------------------------------------------------------- /src/knockapi/types/recipients/__init__.py: -------------------------------------------------------------------------------- 1 | # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | from __future__ import annotations 4 | 5 | from .channel_data import ChannelData as ChannelData 6 | from .subscription import Subscription as Subscription 7 | from .preference_set import PreferenceSet as PreferenceSet 8 | from .slack_channel_data import SlackChannelData as SlackChannelData 9 | from .discord_channel_data import DiscordChannelData as DiscordChannelData 10 | from .ms_teams_channel_data import MsTeamsChannelData as MsTeamsChannelData 11 | from .slack_channel_data_param import SlackChannelDataParam as SlackChannelDataParam 12 | from .discord_channel_data_param import DiscordChannelDataParam as DiscordChannelDataParam 13 | from .ms_teams_channel_data_param import MsTeamsChannelDataParam as MsTeamsChannelDataParam 14 | from .preference_set_channel_types import PreferenceSetChannelTypes as PreferenceSetChannelTypes 15 | from .preference_set_request_param import PreferenceSetRequestParam as PreferenceSetRequestParam 16 | from .preference_set_channel_setting import PreferenceSetChannelSetting as PreferenceSetChannelSetting 17 | from .inline_channel_data_request_param import InlineChannelDataRequestParam as InlineChannelDataRequestParam 18 | from .preference_set_channel_types_param import PreferenceSetChannelTypesParam as PreferenceSetChannelTypesParam 19 | from .inline_preference_set_request_param import InlinePreferenceSetRequestParam as InlinePreferenceSetRequestParam 20 | from .preference_set_channel_type_setting import PreferenceSetChannelTypeSetting as PreferenceSetChannelTypeSetting 21 | from .push_channel_data_tokens_only_param import PushChannelDataTokensOnlyParam as PushChannelDataTokensOnlyParam 22 | from .preference_set_channel_setting_param import PreferenceSetChannelSettingParam as PreferenceSetChannelSettingParam 23 | from .push_channel_data_devices_only_param import PushChannelDataDevicesOnlyParam as PushChannelDataDevicesOnlyParam 24 | from .one_signal_channel_data_player_ids_only import ( 25 | OneSignalChannelDataPlayerIDsOnly as OneSignalChannelDataPlayerIDsOnly, 26 | ) 27 | from .preference_set_channel_type_setting_param import ( 28 | PreferenceSetChannelTypeSettingParam as PreferenceSetChannelTypeSettingParam, 29 | ) 30 | from .aws_sns_push_channel_data_devices_only_param import ( 31 | AwsSnsPushChannelDataDevicesOnlyParam as AwsSnsPushChannelDataDevicesOnlyParam, 32 | ) 33 | from .one_signal_channel_data_player_ids_only_param import ( 34 | OneSignalChannelDataPlayerIDsOnlyParam as OneSignalChannelDataPlayerIDsOnlyParam, 35 | ) 36 | from .aws_sns_push_channel_data_target_arns_only_param import ( 37 | AwsSnsPushChannelDataTargetArnsOnlyParam as AwsSnsPushChannelDataTargetArnsOnlyParam, 38 | ) 39 | -------------------------------------------------------------------------------- /tests/test_utils/test_typing.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | from typing import Generic, TypeVar, cast 4 | 5 | from knockapi._utils import extract_type_var_from_base 6 | 7 | _T = TypeVar("_T") 8 | _T2 = TypeVar("_T2") 9 | _T3 = TypeVar("_T3") 10 | 11 | 12 | class BaseGeneric(Generic[_T]): ... 13 | 14 | 15 | class SubclassGeneric(BaseGeneric[_T]): ... 16 | 17 | 18 | class BaseGenericMultipleTypeArgs(Generic[_T, _T2, _T3]): ... 19 | 20 | 21 | class SubclassGenericMultipleTypeArgs(BaseGenericMultipleTypeArgs[_T, _T2, _T3]): ... 22 | 23 | 24 | class SubclassDifferentOrderGenericMultipleTypeArgs(BaseGenericMultipleTypeArgs[_T2, _T, _T3]): ... 25 | 26 | 27 | def test_extract_type_var() -> None: 28 | assert ( 29 | extract_type_var_from_base( 30 | BaseGeneric[int], 31 | index=0, 32 | generic_bases=cast("tuple[type, ...]", (BaseGeneric,)), 33 | ) 34 | == int 35 | ) 36 | 37 | 38 | def test_extract_type_var_generic_subclass() -> None: 39 | assert ( 40 | extract_type_var_from_base( 41 | SubclassGeneric[int], 42 | index=0, 43 | generic_bases=cast("tuple[type, ...]", (BaseGeneric,)), 44 | ) 45 | == int 46 | ) 47 | 48 | 49 | def test_extract_type_var_multiple() -> None: 50 | typ = BaseGenericMultipleTypeArgs[int, str, None] 51 | 52 | generic_bases = cast("tuple[type, ...]", (BaseGenericMultipleTypeArgs,)) 53 | assert extract_type_var_from_base(typ, index=0, generic_bases=generic_bases) == int 54 | assert extract_type_var_from_base(typ, index=1, generic_bases=generic_bases) == str 55 | assert extract_type_var_from_base(typ, index=2, generic_bases=generic_bases) == type(None) 56 | 57 | 58 | def test_extract_type_var_generic_subclass_multiple() -> None: 59 | typ = SubclassGenericMultipleTypeArgs[int, str, None] 60 | 61 | generic_bases = cast("tuple[type, ...]", (BaseGenericMultipleTypeArgs,)) 62 | assert extract_type_var_from_base(typ, index=0, generic_bases=generic_bases) == int 63 | assert extract_type_var_from_base(typ, index=1, generic_bases=generic_bases) == str 64 | assert extract_type_var_from_base(typ, index=2, generic_bases=generic_bases) == type(None) 65 | 66 | 67 | def test_extract_type_var_generic_subclass_different_ordering_multiple() -> None: 68 | typ = SubclassDifferentOrderGenericMultipleTypeArgs[int, str, None] 69 | 70 | generic_bases = cast("tuple[type, ...]", (BaseGenericMultipleTypeArgs,)) 71 | assert extract_type_var_from_base(typ, index=0, generic_bases=generic_bases) == int 72 | assert extract_type_var_from_base(typ, index=1, generic_bases=generic_bases) == str 73 | assert extract_type_var_from_base(typ, index=2, generic_bases=generic_bases) == type(None) 74 | -------------------------------------------------------------------------------- /src/knockapi/types/message_list_params.py: -------------------------------------------------------------------------------- 1 | # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | from __future__ import annotations 4 | 5 | from typing import List 6 | from typing_extensions import Literal, TypedDict 7 | 8 | from .._types import SequenceNotStr 9 | 10 | __all__ = ["MessageListParams", "InsertedAt"] 11 | 12 | 13 | class MessageListParams(TypedDict, total=False): 14 | after: str 15 | """The cursor to fetch entries after.""" 16 | 17 | before: str 18 | """The cursor to fetch entries before.""" 19 | 20 | channel_id: str 21 | """Limits the results to items with the corresponding channel ID.""" 22 | 23 | engagement_status: List[ 24 | Literal["seen", "unseen", "read", "unread", "archived", "unarchived", "link_clicked", "interacted"] 25 | ] 26 | """Limits the results to messages with the given engagement status.""" 27 | 28 | inserted_at: InsertedAt 29 | 30 | message_ids: SequenceNotStr[str] 31 | """Limits the results to only the message IDs given (max 50). 32 | 33 | Note: when using this option, the results will be subject to any other filters 34 | applied to the query. 35 | """ 36 | 37 | page_size: int 38 | """The number of items per page (defaults to 50).""" 39 | 40 | source: str 41 | """Limits the results to messages triggered by the given workflow key.""" 42 | 43 | status: List[Literal["queued", "sent", "delivered", "delivery_attempted", "undelivered", "not_sent", "bounced"]] 44 | """Limits the results to messages with the given delivery status.""" 45 | 46 | tenant: str 47 | """Limits the results to items with the corresponding tenant.""" 48 | 49 | trigger_data: str 50 | """Limits the results to only messages that were generated with the given data. 51 | 52 | See [trigger data filtering](/api-reference/overview/trigger-data-filtering) for 53 | more information. 54 | """ 55 | 56 | workflow_categories: SequenceNotStr[str] 57 | """Limits the results to messages related to any of the provided categories.""" 58 | 59 | workflow_recipient_run_id: str 60 | """Limits the results to messages for a specific recipient's workflow run.""" 61 | 62 | workflow_run_id: str 63 | """ 64 | Limits the results to messages associated with the top-level workflow run ID 65 | returned by the workflow trigger request. 66 | """ 67 | 68 | 69 | class InsertedAt(TypedDict, total=False): 70 | gt: str 71 | """Limits the results to messages inserted after the given date.""" 72 | 73 | gte: str 74 | """Limits the results to messages inserted after or on the given date.""" 75 | 76 | lt: str 77 | """Limits the results to messages inserted before the given date.""" 78 | 79 | lte: str 80 | """Limits the results to messages inserted before or on the given date.""" 81 | -------------------------------------------------------------------------------- /src/knockapi/types/user_list_messages_params.py: -------------------------------------------------------------------------------- 1 | # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | from __future__ import annotations 4 | 5 | from typing import List 6 | from typing_extensions import Literal, TypedDict 7 | 8 | from .._types import SequenceNotStr 9 | 10 | __all__ = ["UserListMessagesParams", "InsertedAt"] 11 | 12 | 13 | class UserListMessagesParams(TypedDict, total=False): 14 | after: str 15 | """The cursor to fetch entries after.""" 16 | 17 | before: str 18 | """The cursor to fetch entries before.""" 19 | 20 | channel_id: str 21 | """Limits the results to items with the corresponding channel ID.""" 22 | 23 | engagement_status: List[ 24 | Literal["seen", "unseen", "read", "unread", "archived", "unarchived", "link_clicked", "interacted"] 25 | ] 26 | """Limits the results to messages with the given engagement status.""" 27 | 28 | inserted_at: InsertedAt 29 | 30 | message_ids: SequenceNotStr[str] 31 | """Limits the results to only the message IDs given (max 50). 32 | 33 | Note: when using this option, the results will be subject to any other filters 34 | applied to the query. 35 | """ 36 | 37 | page_size: int 38 | """The number of items per page (defaults to 50).""" 39 | 40 | source: str 41 | """Limits the results to messages triggered by the given workflow key.""" 42 | 43 | status: List[Literal["queued", "sent", "delivered", "delivery_attempted", "undelivered", "not_sent", "bounced"]] 44 | """Limits the results to messages with the given delivery status.""" 45 | 46 | tenant: str 47 | """Limits the results to items with the corresponding tenant.""" 48 | 49 | trigger_data: str 50 | """Limits the results to only messages that were generated with the given data. 51 | 52 | See [trigger data filtering](/api-reference/overview/trigger-data-filtering) for 53 | more information. 54 | """ 55 | 56 | workflow_categories: SequenceNotStr[str] 57 | """Limits the results to messages related to any of the provided categories.""" 58 | 59 | workflow_recipient_run_id: str 60 | """Limits the results to messages for a specific recipient's workflow run.""" 61 | 62 | workflow_run_id: str 63 | """ 64 | Limits the results to messages associated with the top-level workflow run ID 65 | returned by the workflow trigger request. 66 | """ 67 | 68 | 69 | class InsertedAt(TypedDict, total=False): 70 | gt: str 71 | """Limits the results to messages inserted after the given date.""" 72 | 73 | gte: str 74 | """Limits the results to messages inserted after or on the given date.""" 75 | 76 | lt: str 77 | """Limits the results to messages inserted before the given date.""" 78 | 79 | lte: str 80 | """Limits the results to messages inserted before or on the given date.""" 81 | -------------------------------------------------------------------------------- /src/knockapi/types/object_list_messages_params.py: -------------------------------------------------------------------------------- 1 | # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | from __future__ import annotations 4 | 5 | from typing import List 6 | from typing_extensions import Literal, TypedDict 7 | 8 | from .._types import SequenceNotStr 9 | 10 | __all__ = ["ObjectListMessagesParams", "InsertedAt"] 11 | 12 | 13 | class ObjectListMessagesParams(TypedDict, total=False): 14 | after: str 15 | """The cursor to fetch entries after.""" 16 | 17 | before: str 18 | """The cursor to fetch entries before.""" 19 | 20 | channel_id: str 21 | """Limits the results to items with the corresponding channel ID.""" 22 | 23 | engagement_status: List[ 24 | Literal["seen", "unseen", "read", "unread", "archived", "unarchived", "link_clicked", "interacted"] 25 | ] 26 | """Limits the results to messages with the given engagement status.""" 27 | 28 | inserted_at: InsertedAt 29 | 30 | message_ids: SequenceNotStr[str] 31 | """Limits the results to only the message IDs given (max 50). 32 | 33 | Note: when using this option, the results will be subject to any other filters 34 | applied to the query. 35 | """ 36 | 37 | page_size: int 38 | """The number of items per page (defaults to 50).""" 39 | 40 | source: str 41 | """Limits the results to messages triggered by the given workflow key.""" 42 | 43 | status: List[Literal["queued", "sent", "delivered", "delivery_attempted", "undelivered", "not_sent", "bounced"]] 44 | """Limits the results to messages with the given delivery status.""" 45 | 46 | tenant: str 47 | """Limits the results to items with the corresponding tenant.""" 48 | 49 | trigger_data: str 50 | """Limits the results to only messages that were generated with the given data. 51 | 52 | See [trigger data filtering](/api-reference/overview/trigger-data-filtering) for 53 | more information. 54 | """ 55 | 56 | workflow_categories: SequenceNotStr[str] 57 | """Limits the results to messages related to any of the provided categories.""" 58 | 59 | workflow_recipient_run_id: str 60 | """Limits the results to messages for a specific recipient's workflow run.""" 61 | 62 | workflow_run_id: str 63 | """ 64 | Limits the results to messages associated with the top-level workflow run ID 65 | returned by the workflow trigger request. 66 | """ 67 | 68 | 69 | class InsertedAt(TypedDict, total=False): 70 | gt: str 71 | """Limits the results to messages inserted after the given date.""" 72 | 73 | gte: str 74 | """Limits the results to messages inserted after or on the given date.""" 75 | 76 | lt: str 77 | """Limits the results to messages inserted before the given date.""" 78 | 79 | lte: str 80 | """Limits the results to messages inserted before or on the given date.""" 81 | -------------------------------------------------------------------------------- /src/knockapi/__init__.py: -------------------------------------------------------------------------------- 1 | # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | import typing as _t 4 | 5 | from . import types 6 | from ._types import NOT_GIVEN, Omit, NoneType, NotGiven, Transport, ProxiesTypes, omit, not_given 7 | from ._utils import file_from_path 8 | from ._client import Knock, Client, Stream, Timeout, Transport, AsyncKnock, AsyncClient, AsyncStream, RequestOptions 9 | from ._models import BaseModel 10 | from ._version import __title__, __version__ 11 | from ._response import APIResponse as APIResponse, AsyncAPIResponse as AsyncAPIResponse 12 | from ._constants import DEFAULT_TIMEOUT, DEFAULT_MAX_RETRIES, DEFAULT_CONNECTION_LIMITS 13 | from ._exceptions import ( 14 | APIError, 15 | KnockError, 16 | ConflictError, 17 | NotFoundError, 18 | APIStatusError, 19 | RateLimitError, 20 | APITimeoutError, 21 | BadRequestError, 22 | APIConnectionError, 23 | AuthenticationError, 24 | InternalServerError, 25 | PermissionDeniedError, 26 | UnprocessableEntityError, 27 | APIResponseValidationError, 28 | ) 29 | from ._base_client import DefaultHttpxClient, DefaultAioHttpClient, DefaultAsyncHttpxClient 30 | from ._utils._logs import setup_logging as _setup_logging 31 | 32 | __all__ = [ 33 | "types", 34 | "__version__", 35 | "__title__", 36 | "NoneType", 37 | "Transport", 38 | "ProxiesTypes", 39 | "NotGiven", 40 | "NOT_GIVEN", 41 | "not_given", 42 | "Omit", 43 | "omit", 44 | "KnockError", 45 | "APIError", 46 | "APIStatusError", 47 | "APITimeoutError", 48 | "APIConnectionError", 49 | "APIResponseValidationError", 50 | "BadRequestError", 51 | "AuthenticationError", 52 | "PermissionDeniedError", 53 | "NotFoundError", 54 | "ConflictError", 55 | "UnprocessableEntityError", 56 | "RateLimitError", 57 | "InternalServerError", 58 | "Timeout", 59 | "RequestOptions", 60 | "Client", 61 | "AsyncClient", 62 | "Stream", 63 | "AsyncStream", 64 | "Knock", 65 | "AsyncKnock", 66 | "file_from_path", 67 | "BaseModel", 68 | "DEFAULT_TIMEOUT", 69 | "DEFAULT_MAX_RETRIES", 70 | "DEFAULT_CONNECTION_LIMITS", 71 | "DefaultHttpxClient", 72 | "DefaultAsyncHttpxClient", 73 | "DefaultAioHttpClient", 74 | ] 75 | 76 | if not _t.TYPE_CHECKING: 77 | from ._utils._resources_proxy import resources as resources 78 | 79 | _setup_logging() 80 | 81 | # Update the __module__ attribute for exported symbols so that 82 | # error messages point to this module instead of the module 83 | # it was originally defined in, e.g. 84 | # knockapi._exceptions.NotFoundError -> knockapi.NotFoundError 85 | __locals = locals() 86 | for __name in __all__: 87 | if not __name.startswith("__"): 88 | try: 89 | __locals[__name].__module__ = "knockapi" 90 | except (TypeError, AttributeError): 91 | # Some of our exported symbols are builtins which we can't set attributes for. 92 | pass 93 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | on: 3 | push: 4 | branches-ignore: 5 | - 'generated' 6 | - 'codegen/**' 7 | - 'integrated/**' 8 | - 'stl-preview-head/**' 9 | - 'stl-preview-base/**' 10 | pull_request: 11 | branches-ignore: 12 | - 'stl-preview-head/**' 13 | - 'stl-preview-base/**' 14 | 15 | jobs: 16 | lint: 17 | timeout-minutes: 10 18 | name: lint 19 | runs-on: ${{ github.repository == 'stainless-sdks/knock-python' && 'depot-ubuntu-24.04' || 'ubuntu-latest' }} 20 | if: github.event_name == 'push' || github.event.pull_request.head.repo.fork 21 | steps: 22 | - uses: actions/checkout@v4 23 | 24 | - name: Install Rye 25 | run: | 26 | curl -sSf https://rye.astral.sh/get | bash 27 | echo "$HOME/.rye/shims" >> $GITHUB_PATH 28 | env: 29 | RYE_VERSION: '0.44.0' 30 | RYE_INSTALL_OPTION: '--yes' 31 | 32 | - name: Install dependencies 33 | run: rye sync --all-features 34 | 35 | - name: Run lints 36 | run: ./scripts/lint 37 | 38 | build: 39 | if: github.event_name == 'push' || github.event.pull_request.head.repo.fork 40 | timeout-minutes: 10 41 | name: build 42 | permissions: 43 | contents: read 44 | id-token: write 45 | runs-on: ${{ github.repository == 'stainless-sdks/knock-python' && 'depot-ubuntu-24.04' || 'ubuntu-latest' }} 46 | steps: 47 | - uses: actions/checkout@v4 48 | 49 | - name: Install Rye 50 | run: | 51 | curl -sSf https://rye.astral.sh/get | bash 52 | echo "$HOME/.rye/shims" >> $GITHUB_PATH 53 | env: 54 | RYE_VERSION: '0.44.0' 55 | RYE_INSTALL_OPTION: '--yes' 56 | 57 | - name: Install dependencies 58 | run: rye sync --all-features 59 | 60 | - name: Run build 61 | run: rye build 62 | 63 | - name: Get GitHub OIDC Token 64 | if: github.repository == 'stainless-sdks/knock-python' 65 | id: github-oidc 66 | uses: actions/github-script@v6 67 | with: 68 | script: core.setOutput('github_token', await core.getIDToken()); 69 | 70 | - name: Upload tarball 71 | if: github.repository == 'stainless-sdks/knock-python' 72 | env: 73 | URL: https://pkg.stainless.com/s 74 | AUTH: ${{ steps.github-oidc.outputs.github_token }} 75 | SHA: ${{ github.sha }} 76 | run: ./scripts/utils/upload-artifact.sh 77 | 78 | test: 79 | timeout-minutes: 10 80 | name: test 81 | runs-on: ${{ github.repository == 'stainless-sdks/knock-python' && 'depot-ubuntu-24.04' || 'ubuntu-latest' }} 82 | if: github.event_name == 'push' || github.event.pull_request.head.repo.fork 83 | steps: 84 | - uses: actions/checkout@v4 85 | 86 | - name: Install Rye 87 | run: | 88 | curl -sSf https://rye.astral.sh/get | bash 89 | echo "$HOME/.rye/shims" >> $GITHUB_PATH 90 | env: 91 | RYE_VERSION: '0.44.0' 92 | RYE_INSTALL_OPTION: '--yes' 93 | 94 | - name: Bootstrap 95 | run: ./scripts/bootstrap 96 | 97 | - name: Run tests 98 | run: ./scripts/test 99 | --------------------------------------------------------------------------------