dex-connector-clickup 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (32) hide show
  1. dex_connector_clickup-0.1.0/.gitignore +16 -0
  2. dex_connector_clickup-0.1.0/LICENSE +21 -0
  3. dex_connector_clickup-0.1.0/PKG-INFO +21 -0
  4. dex_connector_clickup-0.1.0/README.md +9 -0
  5. dex_connector_clickup-0.1.0/examples/get_task/README.md +5 -0
  6. dex_connector_clickup-0.1.0/examples/get_task/__init__.py +3 -0
  7. dex_connector_clickup-0.1.0/examples/get_task/flow.py +70 -0
  8. dex_connector_clickup-0.1.0/examples/get_task/input.example.json +1 -0
  9. dex_connector_clickup-0.1.0/examples/get_task/integration_test.py +106 -0
  10. dex_connector_clickup-0.1.0/examples/get_task/start.py +60 -0
  11. dex_connector_clickup-0.1.0/examples/get_task/worker.py +51 -0
  12. dex_connector_clickup-0.1.0/pyproject.toml +37 -0
  13. dex_connector_clickup-0.1.0/src/dex_connectors/clickup/__init__.py +71 -0
  14. dex_connector_clickup-0.1.0/src/dex_connectors/clickup/_generated/__init__.py +2 -0
  15. dex_connector_clickup-0.1.0/src/dex_connectors/clickup/_generated/config.py +25 -0
  16. dex_connector_clickup-0.1.0/src/dex_connectors/clickup/_generated/connection.py +175 -0
  17. dex_connector_clickup-0.1.0/src/dex_connectors/clickup/_generated/definitions.py +147 -0
  18. dex_connector_clickup-0.1.0/src/dex_connectors/clickup/_generated/mock.py +428 -0
  19. dex_connector_clickup-0.1.0/src/dex_connectors/clickup/_generated/models.py +425 -0
  20. dex_connector_clickup-0.1.0/src/dex_connectors/clickup/_generated/steps.py +402 -0
  21. dex_connector_clickup-0.1.0/src/dex_connectors/clickup/_generated/timestamps.py +60 -0
  22. dex_connector_clickup-0.1.0/src/dex_connectors/clickup/clickupmock/__init__.py +6 -0
  23. dex_connector_clickup-0.1.0/src/dex_connectors/clickup/client.py +602 -0
  24. dex_connector_clickup-0.1.0/src/dex_connectors/clickup/connection.py +8 -0
  25. dex_connector_clickup-0.1.0/src/dex_connectors/clickup/dex-connector.json +277 -0
  26. dex_connector_clickup-0.1.0/src/dex_connectors/clickup/models.py +24 -0
  27. dex_connector_clickup-0.1.0/src/dex_connectors/clickup/operations.py +1013 -0
  28. dex_connector_clickup-0.1.0/src/dex_connectors/clickup/py.typed +0 -0
  29. dex_connector_clickup-0.1.0/src/dex_connectors/clickup/steps.py +11 -0
  30. dex_connector_clickup-0.1.0/tests/test_client.py +252 -0
  31. dex_connector_clickup-0.1.0/tests/test_conformance.py +45 -0
  32. dex_connector_clickup-0.1.0/uv.lock +921 -0
@@ -0,0 +1,16 @@
1
+ .DS_Store
2
+ __pycache__/
3
+ *.py[cod]
4
+ node_modules/
5
+ dist/
6
+ sdkpython/dist/dex_connectors_sdk-0.1.0-py3-none-any.whl
7
+ /.bin/dexcli
8
+ /.bin/dex-server-zd
9
+ /sdkpython/.dexcli-data/
10
+ site/.catalog.yaml
11
+ coverage/
12
+ *.out
13
+ *.test
14
+ go.work
15
+ go.work.sum
16
+ .idea/
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Super Durable
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,21 @@
1
+ Metadata-Version: 2.5
2
+ Name: dex-connector-clickup
3
+ Version: 0.1.0
4
+ Summary: ClickUp connector for Dex Flows
5
+ License-Expression: MIT
6
+ License-File: LICENSE
7
+ Requires-Python: >=3.11
8
+ Requires-Dist: dex-connectors-sdk==0.1.0
9
+ Requires-Dist: dex-python-sdk>=1.28.0
10
+ Requires-Dist: httpx>=0.27
11
+ Description-Content-Type: text/markdown
12
+
13
+ # ClickUp Python connector
14
+
15
+ The package implements the ClickUp `searchTasks`, `getTask`, `createTask`, `updateTask`, `updateTaskTags`, `addComment`, and `findMemberByEmail` operations for Dex Flows. The `taskEvent` webhook Trigger remains Go-only. Install `dex-connector-clickup==0.1.0` alongside a Dex Python application and load its named connection from Dex project configuration. The connection uses a ClickUp personal API token and resolves it before each provider request.
16
+
17
+ The [getTask runnable example](examples/get_task/README.md) uses a static `clickup-workspace` connection and a real Dex Worker and Client. Its integration test exercises a retry and an unwired rejection branch against a local ClickUp stand-in. Run from this directory with `uv sync --locked`, then `uv run pytest tests/ examples/get_task/integration_test.py` while `dexcli dev` is running and `DEX_FLOW_SERVICE_ADDRESS` points to it.
18
+
19
+ `createTask` and `addComment` store a Dex heartbeat checkpoint before an unkeyed write. If a retry sees the checkpoint, it reads back instead of sending the write again; an unconfirmable outcome selects `uncertain`. The provider has no idempotency-key support for these calls. The Python package currently has no live ClickUp authorization or API verification.
20
+
21
+ `getTask` returns custom field JSON values only when Python can represent their numbers exactly. A value that would lose precision selects `invalidResponse` and identifies the field. `updateTaskTags` bounds its sequence of provider requests to 25 seconds; an incomplete sequence retries.
@@ -0,0 +1,9 @@
1
+ # ClickUp Python connector
2
+
3
+ The package implements the ClickUp `searchTasks`, `getTask`, `createTask`, `updateTask`, `updateTaskTags`, `addComment`, and `findMemberByEmail` operations for Dex Flows. The `taskEvent` webhook Trigger remains Go-only. Install `dex-connector-clickup==0.1.0` alongside a Dex Python application and load its named connection from Dex project configuration. The connection uses a ClickUp personal API token and resolves it before each provider request.
4
+
5
+ The [getTask runnable example](examples/get_task/README.md) uses a static `clickup-workspace` connection and a real Dex Worker and Client. Its integration test exercises a retry and an unwired rejection branch against a local ClickUp stand-in. Run from this directory with `uv sync --locked`, then `uv run pytest tests/ examples/get_task/integration_test.py` while `dexcli dev` is running and `DEX_FLOW_SERVICE_ADDRESS` points to it.
6
+
7
+ `createTask` and `addComment` store a Dex heartbeat checkpoint before an unkeyed write. If a retry sees the checkpoint, it reads back instead of sending the write again; an unconfirmable outcome selects `uncertain`. The provider has no idempotency-key support for these calls. The Python package currently has no live ClickUp authorization or API verification.
8
+
9
+ `getTask` returns custom field JSON values only when Python can represent their numbers exactly. A value that would lose precision selects `invalidResponse` and identifies the field. `updateTaskTags` bounds its sequence of provider requests to 25 seconds; an incomplete sequence retries.
@@ -0,0 +1,5 @@
1
+ # Read a ClickUp task
2
+
3
+ The Flow uses the static `clickup-workspace` connection and the `getTask` Query. Create that connection in Dex Web using the ClickUp personal API token described in the [connector guide](../../../README.md). From the `python/` directory, run `uv sync --locked`, start `uv run python -m examples.get_task.worker`, then run `uv run python -m examples.get_task.start clickup-task-1 examples/get_task/input.example.json` against the same Dex stack. Set `DEX_FLOW_SERVICE_ADDRESS` when Dex runs on a nondefault port.
4
+
5
+ The example stores the returned task in a Dex Attribute. An unwired optional branch fails the Flow. The integration test runs the same Flow through a real Dex Worker and Client with an inert local provider stand-in; it does not verify live ClickUp authorization.
@@ -0,0 +1,3 @@
1
+ # Copyright (c) 2026 Super Durable
2
+ # SPDX-License-Identifier: MIT
3
+ """Runnable ClickUp task read example."""
@@ -0,0 +1,70 @@
1
+ # Copyright (c) 2026 Super Durable
2
+ # SPDX-License-Identifier: MIT
3
+ """Read one ClickUp task through a typed Dex Flow."""
4
+
5
+ from dataclasses import dataclass, field
6
+
7
+ import dex
8
+ from dex_connectors.sdk import QueryResult
9
+
10
+ from dex_connectors.clickup import Connection, GetTaskInput, Task, new_get_task_step
11
+
12
+ CONNECTION_NAME = "clickup-workspace"
13
+ FLOW_TYPE = "ClickUpGetTaskPython"
14
+ TASK_RESULT = dex.Attribute("clickup-get-task-result", Task)
15
+
16
+
17
+ @dataclass(frozen=True, slots=True)
18
+ class GetTaskRequest:
19
+ """Task ID selected for one Flow run."""
20
+
21
+ task_id: str = field(metadata={"dex_json_name": "taskId"})
22
+
23
+ def to_operation_input(self) -> GetTaskInput:
24
+ """Name the ClickUp task to read."""
25
+ return GetTaskInput(task_id=self.task_id)
26
+
27
+
28
+ # dex:group group-id:clickup-task group-label:"ClickUp task"
29
+ # dex:explanation text:"Store the task returned by ClickUp and complete the Flow."
30
+ class CompleteTaskRead(dex.Step[QueryResult[Task]]):
31
+ """Persist the provider task result."""
32
+
33
+ def execute(self, context: dex.Context, input: QueryResult[Task]) -> dex.StepDecision:
34
+ """Complete after saving the task for external reads."""
35
+ TASK_RESULT.set(context, input.value)
36
+ return dex.graceful_complete(input.value)
37
+
38
+
39
+ class GetTaskFlow(dex.Flow[GetTaskRequest]):
40
+ """Read one task through the static ClickUp connection."""
41
+
42
+ def __init__(self, connection: Connection) -> None:
43
+ if connection.reference.name != CONNECTION_NAME:
44
+ raise ValueError("getTask requires the static ClickUp connection")
45
+ self.complete = CompleteTaskRead()
46
+ self.read = new_get_task_step(
47
+ step_type="ReadClickUpTask",
48
+ step_input_type=GetTaskRequest,
49
+ annotations={
50
+ "groupId": "clickup-task",
51
+ "groupLabel": "ClickUp task",
52
+ "explanation": "Read one ClickUp task with its custom fields.",
53
+ },
54
+ connection=connection,
55
+ connection_name=CONNECTION_NAME,
56
+ map_to_operation_input=GetTaskRequest.to_operation_input,
57
+ found=self.complete,
58
+ )
59
+
60
+ def get_flow_type(self) -> str:
61
+ """Return the stable Flow identity."""
62
+ return FLOW_TYPE
63
+
64
+ def get_steps(self) -> dex.StepList[GetTaskRequest]:
65
+ """Register the provider Step and completion Step."""
66
+ return dex.StepList.start_step(self.read).other_steps(self.complete)
67
+
68
+ def get_persistence_schema(self) -> dex.PersistenceSchema:
69
+ """Register the retained task Attribute."""
70
+ return dex.PersistenceSchema.of(TASK_RESULT)
@@ -0,0 +1 @@
1
+ {"taskId":"86b2x4k7q"}
@@ -0,0 +1,106 @@
1
+ # Copyright (c) 2026 Super Durable
2
+ # SPDX-License-Identifier: MIT
3
+ """Exercise ClickUp getTask through a real Dex Worker and Client."""
4
+
5
+ import asyncio
6
+ import json
7
+ import os
8
+ import tempfile
9
+ from datetime import timedelta
10
+ from pathlib import Path
11
+ from uuid import uuid4
12
+
13
+ import dex
14
+ import httpx
15
+ import pytest
16
+ from dex_connectors.sdk.projectconfig import load_from_environment
17
+
18
+ from dex_connectors.clickup import Task, new_project_connection
19
+
20
+ from .flow import CONNECTION_NAME, GetTaskFlow, GetTaskRequest
21
+
22
+
23
+ @pytest.mark.asyncio
24
+ async def test_get_task_retries_and_fails_unwired_rejection_in_real_dex(
25
+ monkeypatch: pytest.MonkeyPatch,
26
+ ) -> None:
27
+ """Cover Worker registration, a rate-limited retry, and an optional branch."""
28
+ server_address = os.environ["DEX_FLOW_SERVICE_ADDRESS"]
29
+ requests: list[httpx.Request] = []
30
+
31
+ def answer(request: httpx.Request) -> httpx.Response:
32
+ requests.append(request)
33
+ if request.url.path.endswith("/rejected"):
34
+ return httpx.Response(403, json={"ECODE": "ACCESS_001"})
35
+ if len(requests) == 1:
36
+ return httpx.Response(429, headers={"Retry-After": "1"})
37
+ return httpx.Response(
38
+ 200,
39
+ json={
40
+ "id": "86b2x4k7q",
41
+ "name": "Escalation: Fix login",
42
+ "status": {"status": "open", "type": "open"},
43
+ "assignees": [],
44
+ "tags": [],
45
+ },
46
+ )
47
+
48
+ with tempfile.TemporaryDirectory(prefix="clickup-python-dex-") as directory:
49
+ connections_path = Path(directory) / "connections.json"
50
+ connections_path.write_text(
51
+ json.dumps(
52
+ {
53
+ "schemaVersion": "connectors.dex.dev/local-connections/v1alpha1",
54
+ "connections": [
55
+ {
56
+ "connectorId": "clickup",
57
+ "connectionName": CONNECTION_NAME,
58
+ "modulePath": "github.com/superdurable/dex-connectors-library/connectors/clickup",
59
+ "provider": "clickup",
60
+ "configuration": {},
61
+ "credentials": {"api_token": "pk_inert_test_token"},
62
+ }
63
+ ],
64
+ "triggerBindings": [],
65
+ }
66
+ )
67
+ )
68
+ connections_path.chmod(0o600)
69
+ monkeypatch.setenv("DEX_CONNECTOR_CONFIG_FILE", str(connections_path))
70
+ project = await load_from_environment({"DEX_CONNECTOR_CONFIG_FILE": str(connections_path)})
71
+ async with httpx.AsyncClient(transport=httpx.MockTransport(answer)) as provider_http_client:
72
+ connection = new_project_connection(project, CONNECTION_NAME, provider_http_client)
73
+ flow = GetTaskFlow(connection)
74
+ registry = dex.Registry([flow], allow_async_handlers=True)
75
+ cache = dex.open_blob_cache(dex.BlobCacheConfig(str(Path(directory) / "blobs"), 1 << 24))
76
+ try:
77
+ worker = dex.AsyncWorker(registry, cache, dex.WorkerOptions(server_address=server_address))
78
+ worker_task = asyncio.create_task(worker.start())
79
+ try:
80
+ await worker.wait_pull_registered(timeout=15)
81
+ async with dex.AsyncClient(
82
+ registry, cache, dex.ClientOptions(server_address=server_address)
83
+ ) as dex_client:
84
+ successful_flow_id = f"clickup-python-get-{uuid4().hex}"
85
+ await dex_client.start_flow(flow, successful_flow_id, GetTaskRequest("86b2x4k7q"))
86
+ success = await asyncio.wait_for(
87
+ dex_client.wait_for_flow(successful_flow_id, timedelta(seconds=20)), 30
88
+ )
89
+ assert success.status == dex.FlowStatus.COMPLETED, success.error_message
90
+ assert success.single_output(Task).id == "86b2x4k7q"
91
+ assert len(requests) == 2
92
+
93
+ rejected_flow_id = f"clickup-python-get-{uuid4().hex}"
94
+ await dex_client.start_flow(flow, rejected_flow_id, GetTaskRequest("rejected"))
95
+ rejected = await asyncio.wait_for(
96
+ dex_client.wait_for_flow(rejected_flow_id, timedelta(seconds=20)), 30
97
+ )
98
+ assert rejected.status == dex.FlowStatus.FAILED
99
+ assert "providerRejected" in (rejected.error_message or "")
100
+ finally:
101
+ await worker.stop()
102
+ await worker_task
103
+ finally:
104
+ cache.close()
105
+ await connection.aclose()
106
+ await project.close()
@@ -0,0 +1,60 @@
1
+ # Copyright (c) 2026 Super Durable
2
+ # SPDX-License-Identifier: MIT
3
+ """Start one ClickUp task-read Flow."""
4
+
5
+ import argparse
6
+ import asyncio
7
+ import os
8
+ import tempfile
9
+ from pathlib import Path
10
+
11
+ import dex
12
+ from dex_connectors.sdk.projectconfig import load_from_environment
13
+
14
+ from dex_connectors.clickup import new_project_connection
15
+
16
+ from .flow import CONNECTION_NAME, GetTaskFlow, GetTaskRequest
17
+
18
+
19
+ async def start_task_read(flow_id: str, input_file: Path) -> str:
20
+ """Decode one safe task ID and start its Flow."""
21
+ with input_file.open("rb") as source:
22
+ encoded = source.read(65_537)
23
+ if len(encoded) > 65_536:
24
+ raise ValueError("ClickUp input exceeds 65536 bytes")
25
+ input_value = (
26
+ dex.CodecRegistry()
27
+ .resolve(GetTaskRequest)
28
+ .decode(dex.Value(dex.WireKind.JSON, encoded.decode("utf-8")))
29
+ )
30
+ project = await load_from_environment()
31
+ connection = new_project_connection(project, CONNECTION_NAME)
32
+ try:
33
+ flow = GetTaskFlow(connection)
34
+ registry = dex.Registry([flow], allow_async_handlers=True)
35
+ with tempfile.TemporaryDirectory(prefix="clickup-python-start-blobs-") as cache_directory:
36
+ cache = dex.open_blob_cache(dex.BlobCacheConfig(cache_directory, 1 << 24))
37
+ try:
38
+ server_address = os.environ.get("DEX_FLOW_SERVICE_ADDRESS", "localhost:8801")
39
+ async with dex.AsyncClient(
40
+ registry, cache, dex.ClientOptions(server_address=server_address)
41
+ ) as client:
42
+ return await client.start_flow(flow, flow_id, input_value)
43
+ finally:
44
+ cache.close()
45
+ finally:
46
+ await connection.aclose()
47
+ await project.close()
48
+
49
+
50
+ def main() -> None:
51
+ """Take a unique Flow ID and JSON input path."""
52
+ parser = argparse.ArgumentParser(description="Start a ClickUp task read")
53
+ parser.add_argument("flow_id")
54
+ parser.add_argument("input_file", type=Path)
55
+ arguments = parser.parse_args()
56
+ print(asyncio.run(start_task_read(arguments.flow_id, arguments.input_file)))
57
+
58
+
59
+ if __name__ == "__main__":
60
+ main()
@@ -0,0 +1,51 @@
1
+ # Copyright (c) 2026 Super Durable
2
+ # SPDX-License-Identifier: MIT
3
+ """Worker entrypoint for the ClickUp getTask example."""
4
+
5
+ import asyncio
6
+ import os
7
+ import tempfile
8
+ from pathlib import Path
9
+
10
+ import dex
11
+ from dex_connectors.sdk.projectconfig import load_from_environment
12
+
13
+ from dex_connectors.clickup import new_project_connection
14
+
15
+ from .flow import CONNECTION_NAME, GetTaskFlow
16
+
17
+
18
+ async def run_worker() -> None:
19
+ """Load the named connection and serve task reads."""
20
+ project = await load_from_environment()
21
+ connection = None
22
+ cache = None
23
+ try:
24
+ connection = new_project_connection(project, CONNECTION_NAME)
25
+ registry = dex.Registry([GetTaskFlow(connection)], allow_async_handlers=True)
26
+ cache_directory = os.environ.get(
27
+ "DEX_BLOB_CACHE_DIR", str(Path(tempfile.gettempdir()) / "dex-clickup-get-task-blobs")
28
+ )
29
+ cache = dex.open_blob_cache(dex.BlobCacheConfig(cache_directory, 1 << 30))
30
+ worker = dex.AsyncWorker(
31
+ registry,
32
+ cache,
33
+ dex.WorkerOptions(server_address=os.environ.get("DEX_FLOW_SERVICE_ADDRESS", "localhost:8801")),
34
+ )
35
+ async with worker:
36
+ await worker.start()
37
+ finally:
38
+ if connection is not None:
39
+ await connection.aclose()
40
+ if cache is not None:
41
+ cache.close()
42
+ await project.close()
43
+
44
+
45
+ def main() -> None:
46
+ """Run until the Worker stops."""
47
+ asyncio.run(run_worker())
48
+
49
+
50
+ if __name__ == "__main__":
51
+ main()
@@ -0,0 +1,37 @@
1
+ [build-system]
2
+ requires = ["hatchling>=1.27"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [project]
6
+ name = "dex-connector-clickup"
7
+ version = "0.1.0"
8
+ description = "ClickUp connector for Dex Flows"
9
+ readme = "README.md"
10
+ requires-python = ">=3.11"
11
+ license = "MIT"
12
+ dependencies = ["dex-connectors-sdk==0.1.0", "dex-python-sdk>=1.28.0", "httpx>=0.27"]
13
+
14
+ [dependency-groups]
15
+ dev = ["pytest>=8", "pytest-asyncio>=0.24", "mypy>=1.13", "ruff>=0.7", "pyyaml>=6"]
16
+
17
+ [tool.hatch.build.targets.wheel]
18
+ packages = ["src/dex_connectors"]
19
+
20
+ [tool.pytest.ini_options]
21
+ testpaths = ["tests"]
22
+ pythonpath = [".", "src"]
23
+ asyncio_mode = "auto"
24
+ asyncio_default_fixture_loop_scope = "function"
25
+
26
+ [tool.mypy]
27
+ python_version = "3.11"
28
+ strict = true
29
+ mypy_path = "src"
30
+ explicit_package_bases = true
31
+
32
+ [tool.ruff]
33
+ target-version = "py311"
34
+ line-length = 110
35
+
36
+ [tool.ruff.lint]
37
+ select = ["E", "F", "I", "UP", "B"]
@@ -0,0 +1,71 @@
1
+ # Copyright (c) 2026 Super Durable
2
+ # SPDX-License-Identifier: MIT
3
+ """Dex-native ClickUp task operations."""
4
+
5
+ from .client import Client as Client
6
+ from .client import Config as Config
7
+ from .client import Credentials as Credentials
8
+ from .connection import Connection as Connection
9
+ from .connection import new_connection as new_connection
10
+ from .connection import new_connection_with_operations as new_connection_with_operations
11
+ from .connection import new_project_connection as new_project_connection
12
+ from .models import AddCommentInput as AddCommentInput
13
+ from .models import AddCommentOutput as AddCommentOutput
14
+ from .models import CreateTaskInput as CreateTaskInput
15
+ from .models import CreateTaskOutput as CreateTaskOutput
16
+ from .models import CustomFieldInput as CustomFieldInput
17
+ from .models import CustomFieldValue as CustomFieldValue
18
+ from .models import FindMemberByEmailInput as FindMemberByEmailInput
19
+ from .models import GetTaskInput as GetTaskInput
20
+ from .models import Member as Member
21
+ from .models import SearchTasksInput as SearchTasksInput
22
+ from .models import SearchTasksOutput as SearchTasksOutput
23
+ from .models import Task as Task
24
+ from .models import TaskStatus as TaskStatus
25
+ from .models import UpdateTaskInput as UpdateTaskInput
26
+ from .models import UpdateTaskOutput as UpdateTaskOutput
27
+ from .models import UpdateTaskTagsInput as UpdateTaskTagsInput
28
+ from .models import UpdateTaskTagsOutput as UpdateTaskTagsOutput
29
+ from .models import User as User
30
+ from .steps import new_add_comment_step as new_add_comment_step
31
+ from .steps import new_create_task_step as new_create_task_step
32
+ from .steps import new_find_member_by_email_step as new_find_member_by_email_step
33
+ from .steps import new_get_task_step as new_get_task_step
34
+ from .steps import new_search_tasks_step as new_search_tasks_step
35
+ from .steps import new_update_task_step as new_update_task_step
36
+ from .steps import new_update_task_tags_step as new_update_task_tags_step
37
+
38
+ __all__ = [
39
+ "AddCommentInput",
40
+ "AddCommentOutput",
41
+ "Client",
42
+ "Config",
43
+ "Connection",
44
+ "CreateTaskInput",
45
+ "CreateTaskOutput",
46
+ "Credentials",
47
+ "CustomFieldInput",
48
+ "CustomFieldValue",
49
+ "FindMemberByEmailInput",
50
+ "GetTaskInput",
51
+ "Member",
52
+ "SearchTasksInput",
53
+ "SearchTasksOutput",
54
+ "Task",
55
+ "TaskStatus",
56
+ "UpdateTaskInput",
57
+ "UpdateTaskOutput",
58
+ "UpdateTaskTagsInput",
59
+ "UpdateTaskTagsOutput",
60
+ "User",
61
+ "new_add_comment_step",
62
+ "new_connection",
63
+ "new_connection_with_operations",
64
+ "new_create_task_step",
65
+ "new_find_member_by_email_step",
66
+ "new_get_task_step",
67
+ "new_project_connection",
68
+ "new_search_tasks_step",
69
+ "new_update_task_step",
70
+ "new_update_task_tags_step",
71
+ ]
@@ -0,0 +1,2 @@
1
+ # Copyright (c) 2026 Super Durable
2
+ # SPDX-License-Identifier: MIT
@@ -0,0 +1,25 @@
1
+ # Copyright (c) 2026 Super Durable
2
+ # SPDX-License-Identifier: MIT
3
+ # ruff: noqa
4
+
5
+ from dataclasses import dataclass
6
+
7
+ from dex_connectors.sdk import SecretString
8
+
9
+
10
+ @dataclass(frozen=True, slots=True)
11
+ class Config:
12
+
13
+ max_response_bytes: int = 4194304
14
+ webhook_max_body_bytes: int = 1048576
15
+
16
+ setattr(Config, '__module__', 'dex_connectors.clickup.client')
17
+
18
+
19
+ @dataclass(frozen=True, slots=True)
20
+ class Credentials:
21
+
22
+ api_token: SecretString
23
+ webhook_secret: SecretString
24
+
25
+ setattr(Credentials, '__module__', 'dex_connectors.clickup.client')