dex-connector-google-docs 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 (39) hide show
  1. dex_connector_google_docs-0.1.0/.gitignore +16 -0
  2. dex_connector_google_docs-0.1.0/LICENSE +21 -0
  3. dex_connector_google_docs-0.1.0/PKG-INFO +25 -0
  4. dex_connector_google_docs-0.1.0/README.md +12 -0
  5. dex_connector_google_docs-0.1.0/examples/policy_read/README.md +30 -0
  6. dex_connector_google_docs-0.1.0/examples/policy_read/__init__.py +3 -0
  7. dex_connector_google_docs-0.1.0/examples/policy_read/flow.py +68 -0
  8. dex_connector_google_docs-0.1.0/examples/policy_read/integration_test.py +93 -0
  9. dex_connector_google_docs-0.1.0/examples/policy_read/start.py +52 -0
  10. dex_connector_google_docs-0.1.0/examples/policy_read/worker.py +50 -0
  11. dex_connector_google_docs-0.1.0/pyproject.toml +41 -0
  12. dex_connector_google_docs-0.1.0/src/dex_connectors/google_docs/__init__.py +50 -0
  13. dex_connector_google_docs-0.1.0/src/dex_connectors/google_docs/_generated/__init__.py +2 -0
  14. dex_connector_google_docs-0.1.0/src/dex_connectors/google_docs/_generated/config.py +32 -0
  15. dex_connector_google_docs-0.1.0/src/dex_connectors/google_docs/_generated/connection.py +254 -0
  16. dex_connector_google_docs-0.1.0/src/dex_connectors/google_docs/_generated/definitions.py +102 -0
  17. dex_connector_google_docs-0.1.0/src/dex_connectors/google_docs/_generated/mock.py +323 -0
  18. dex_connector_google_docs-0.1.0/src/dex_connectors/google_docs/_generated/models.py +211 -0
  19. dex_connector_google_docs-0.1.0/src/dex_connectors/google_docs/_generated/refresh.py +9 -0
  20. dex_connector_google_docs-0.1.0/src/dex_connectors/google_docs/_generated/steps.py +255 -0
  21. dex_connector_google_docs-0.1.0/src/dex_connectors/google_docs/_generated/timestamps.py +60 -0
  22. dex_connector_google_docs-0.1.0/src/dex_connectors/google_docs/client.py +271 -0
  23. dex_connector_google_docs-0.1.0/src/dex_connectors/google_docs/connection.py +12 -0
  24. dex_connector_google_docs-0.1.0/src/dex_connectors/google_docs/create.py +547 -0
  25. dex_connector_google_docs-0.1.0/src/dex_connectors/google_docs/dex-connector.json +183 -0
  26. dex_connector_google_docs-0.1.0/src/dex_connectors/google_docs/docsmock/__init__.py +6 -0
  27. dex_connector_google_docs-0.1.0/src/dex_connectors/google_docs/document.py +222 -0
  28. dex_connector_google_docs-0.1.0/src/dex_connectors/google_docs/json_values.py +23 -0
  29. dex_connector_google_docs-0.1.0/src/dex_connectors/google_docs/models.py +31 -0
  30. dex_connector_google_docs-0.1.0/src/dex_connectors/google_docs/operations.py +630 -0
  31. dex_connector_google_docs-0.1.0/src/dex_connectors/google_docs/query_values.py +16 -0
  32. dex_connector_google_docs-0.1.0/src/dex_connectors/google_docs/steps.py +17 -0
  33. dex_connector_google_docs-0.1.0/tests/refresh_agreement_cases.json +1309 -0
  34. dex_connector_google_docs-0.1.0/tests/test_conformance.py +47 -0
  35. dex_connector_google_docs-0.1.0/tests/test_create_timestamp.py +17 -0
  36. dex_connector_google_docs-0.1.0/tests/test_json_values.py +15 -0
  37. dex_connector_google_docs-0.1.0/tests/test_query_values.py +36 -0
  38. dex_connector_google_docs-0.1.0/tests/test_refresh_agreement.py +278 -0
  39. dex_connector_google_docs-0.1.0/uv.lock +934 -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,25 @@
1
+ Metadata-Version: 2.5
2
+ Name: dex-connector-google-docs
3
+ Version: 0.1.0
4
+ Summary: Dex-native Google Docs connector
5
+ Project-URL: Source, https://github.com/superdurable/dex-connectors-library/tree/main/connectors/google/docs/python
6
+ License-Expression: MIT
7
+ License-File: LICENSE
8
+ Requires-Python: >=3.11
9
+ Requires-Dist: dex-connectors-sdk==0.7.0
10
+ Requires-Dist: dex-python-sdk>=1.28.0
11
+ Requires-Dist: httpx>=0.27
12
+ Description-Content-Type: text/markdown
13
+
14
+ # Google Docs Python connector
15
+
16
+ Dex-native Google Docs operations, with operation-specific Step factories for
17
+ `getDocumentText`, `createDocument`, `replaceDocumentText`, and `appendText`.
18
+ The package requires Connector SDK 0.7.0. Use `new_project_connection` for the
19
+ generated Google OAuth or Workspace domain delegation credential refresh wiring.
20
+ Provider creation timestamps must be valid Go JSON timestamps; invalid values
21
+ fail before a document Result is stored.
22
+
23
+ The [policy read example](examples/policy_read/README.md) shows the static
24
+ connection name, FDG generation, Worker, and Flow starter. See the
25
+ [parent connector README](../README.md) for authorization and operation guidance.
@@ -0,0 +1,12 @@
1
+ # Google Docs Python connector
2
+
3
+ Dex-native Google Docs operations, with operation-specific Step factories for
4
+ `getDocumentText`, `createDocument`, `replaceDocumentText`, and `appendText`.
5
+ The package requires Connector SDK 0.7.0. Use `new_project_connection` for the
6
+ generated Google OAuth or Workspace domain delegation credential refresh wiring.
7
+ Provider creation timestamps must be valid Go JSON timestamps; invalid values
8
+ fail before a document Result is stored.
9
+
10
+ The [policy read example](examples/policy_read/README.md) shows the static
11
+ connection name, FDG generation, Worker, and Flow starter. See the
12
+ [parent connector README](../README.md) for authorization and operation guidance.
@@ -0,0 +1,30 @@
1
+ # Google Docs policy read
2
+
3
+ This Flow reads the first tab of a Google Doc as plain text. It uses the static
4
+ `google-docs-policy` connection and fails if an optional provider branch is selected.
5
+
6
+ From `connectors/google/docs/python`, install with `uv sync --locked` and generate
7
+ strict FDG 2.0 with:
8
+
9
+ ```sh
10
+ mkdir -p build
11
+ dexcli visualize ./examples/policy_read/flow.py --language python \
12
+ --python .venv/bin/python --schema-version 2.0 --json \
13
+ --out ./build/google-docs-policy-read
14
+ ```
15
+
16
+ Start `dexcli dev -flow-rendering-dir ./build`, configure the Google OAuth
17
+ `google-docs-policy` connection in Dex Web following the parent README, then
18
+ export the owner-only `DEX_CONNECTOR_CONFIG_FILE` path and
19
+ `DEX_FLOW_SERVICE_ADDRESS` from that project. Run the Worker and start a
20
+ Flow with a unique ID and a document ID from the
21
+ `/document/d/{documentId}/edit` portion of its Google Docs URL:
22
+
23
+ ```sh
24
+ uv run python -m examples.policy_read.worker
25
+ uv run python -m examples.policy_read.start policy-read-001 YOUR_DOCUMENT_ID
26
+ ```
27
+
28
+ The Dex integration test uses a local provider fake and needs no Google
29
+ authorization: `uv run pytest examples/policy_read/integration_test.py`
30
+ while `dexcli dev` is running.
@@ -0,0 +1,3 @@
1
+ # Copyright (c) 2026 Super Durable
2
+ # SPDX-License-Identifier: MIT
3
+ """Google Docs policy read example."""
@@ -0,0 +1,68 @@
1
+ # Copyright (c) 2026 Super Durable
2
+ # SPDX-License-Identifier: MIT
3
+ """Read one Google Doc through a 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.google_docs import (
11
+ Connection,
12
+ GetDocumentTextInput,
13
+ GetDocumentTextOutput,
14
+ new_get_document_text_step,
15
+ )
16
+
17
+ CONNECTION_NAME = "google-docs-policy"
18
+
19
+
20
+ @dataclass(frozen=True, slots=True)
21
+ class PolicyReadRequest:
22
+ """Identify the Google Doc whose first tab should be read."""
23
+
24
+ document_id: str = field(default="", metadata={"dex_json_name": "documentId"})
25
+
26
+
27
+ # dex:group group-id:google-docs group-label:"Google Docs"
28
+ # dex:explanation text:"Complete with the bounded text returned by Google Docs."
29
+ class _CompletePolicyRead(dex.Step[QueryResult[GetDocumentTextOutput]]):
30
+ def get_step_type(self) -> str:
31
+ return "CompleteGoogleDocsPolicyRead"
32
+
33
+ def execute(
34
+ self, context: dex.Context, input: QueryResult[GetDocumentTextOutput]
35
+ ) -> dex.StepDecision:
36
+ return dex.graceful_complete(input.value)
37
+
38
+
39
+ class PolicyReadFlow(dex.Flow[PolicyReadRequest]):
40
+ """Read one policy document through the static Google Docs connection."""
41
+
42
+ def __init__(self, connection: Connection) -> None:
43
+ if connection.reference.name != CONNECTION_NAME:
44
+ raise ValueError("policy read requires the static Google Docs connection")
45
+ self._complete = _CompletePolicyRead()
46
+ self._read = new_get_document_text_step(
47
+ step_type="ReadGoogleDocsPolicy",
48
+ step_input_type=PolicyReadRequest,
49
+ annotations={
50
+ "groupId": "google-docs",
51
+ "groupLabel": "Google Docs",
52
+ "explanation": "Read the first tab as plain text with pending suggestions rejected.",
53
+ },
54
+ connection=connection,
55
+ connection_name=CONNECTION_NAME,
56
+ map_to_operation_input=lambda request: GetDocumentTextInput(
57
+ document_id=request.document_id, format="plainText"
58
+ ),
59
+ read=self._complete,
60
+ )
61
+
62
+ def get_flow_type(self) -> str:
63
+ """Return the stable Flow identity."""
64
+ return "GoogleDocsPolicyRead"
65
+
66
+ def get_steps(self) -> dex.StepList[PolicyReadRequest]:
67
+ """Register the read and completion Steps."""
68
+ return dex.StepList.start_step(self._read).other_steps(self._complete)
@@ -0,0 +1,93 @@
1
+ # Copyright (c) 2026 Super Durable
2
+ # SPDX-License-Identifier: MIT
3
+ """Exercise the checked-in Flow with a real Dex Worker and Client."""
4
+
5
+ import asyncio
6
+ import os
7
+ from datetime import timedelta
8
+ from pathlib import Path
9
+ from uuid import uuid4
10
+
11
+ import dex
12
+ import httpx
13
+ import pytest
14
+ from dex_connectors.sdk import ConnectionRef, SecretString, StaticCredentialProvider
15
+
16
+ from dex_connectors.google_docs import Client, Config, Credentials, GetDocumentTextOutput, new_connection
17
+
18
+ from .flow import CONNECTION_NAME, PolicyReadFlow, PolicyReadRequest
19
+
20
+
21
+ @pytest.mark.asyncio
22
+ async def test_read_retries_and_unwired_not_found_fails(tmp_path: Path) -> None:
23
+ """Verify the read's retry and optional branch through real Dex state."""
24
+ requests: list[httpx.Request] = []
25
+
26
+ def answer(request: httpx.Request) -> httpx.Response:
27
+ requests.append(request)
28
+ if request.url.path.endswith("/missing"):
29
+ return httpx.Response(404, json={"error": {"code": 404}})
30
+ if len(requests) == 1:
31
+ return httpx.Response(503, json={"error": {"code": 503}})
32
+ return httpx.Response(200, json={
33
+ "documentId": "policy123",
34
+ "title": "Policy",
35
+ "revisionId": "rev-1",
36
+ "tabs": [{
37
+ "tabProperties": {"tabId": "t.0"},
38
+ "documentTab": {"body": {"content": [
39
+ {"endIndex": 1, "sectionBreak": {}},
40
+ {"startIndex": 1, "endIndex": 8, "paragraph": {
41
+ "elements": [{"textRun": {"content": "Policy\n"}}]
42
+ }},
43
+ ]}},
44
+ }],
45
+ })
46
+
47
+ reference = ConnectionRef("google", CONNECTION_NAME)
48
+ credentials = StaticCredentialProvider({
49
+ reference: Credentials(access_token=SecretString("inert-docs-token"))
50
+ })
51
+ async with httpx.AsyncClient(transport=httpx.MockTransport(answer)) as provider_http_client:
52
+ provider = Client(
53
+ Config(docs_endpoint="http://127.0.0.1:44350", drive_endpoint="http://127.0.0.1:44350"),
54
+ credentials,
55
+ provider_http_client,
56
+ )
57
+ connection = new_connection(provider, reference)
58
+ flow = PolicyReadFlow(connection)
59
+ registry = dex.Registry([flow], allow_async_handlers=True)
60
+ cache = dex.open_blob_cache(dex.BlobCacheConfig(str(tmp_path / "blobs"), 1 << 24))
61
+ address = os.environ["DEX_FLOW_SERVICE_ADDRESS"]
62
+ worker = dex.AsyncWorker(registry, cache, dex.WorkerOptions(server_address=address))
63
+ worker_task = asyncio.create_task(worker.start())
64
+ try:
65
+ await worker.wait_pull_registered(timeout=20)
66
+ async with dex.AsyncClient(
67
+ registry, cache, dex.ClientOptions(server_address=address)
68
+ ) as client:
69
+ successful_id = f"google-docs-python-{uuid4().hex}"
70
+ await client.start_flow(flow, successful_id, PolicyReadRequest("policy123"))
71
+ successful = await asyncio.wait_for(
72
+ client.wait_for_flow(successful_id, timedelta(seconds=20)), 30
73
+ )
74
+ assert successful.status == dex.FlowStatus.COMPLETED, successful.error_message
75
+ output = successful.single_output(GetDocumentTextOutput)
76
+ assert output.document_id == "policy123"
77
+ assert output.text == "Policy"
78
+ assert len(requests) == 2
79
+
80
+ missing_id = f"google-docs-python-{uuid4().hex}"
81
+ await client.start_flow(flow, missing_id, PolicyReadRequest("missing"))
82
+ missing = await asyncio.wait_for(
83
+ client.wait_for_flow(missing_id, timedelta(seconds=20)), 30
84
+ )
85
+ assert missing.status == dex.FlowStatus.FAILED
86
+ assert missing.error_message is not None
87
+ assert "notFound" in missing.error_message
88
+ assert len(requests) == 3
89
+ finally:
90
+ await worker.stop()
91
+ await worker_task
92
+ cache.close()
93
+ await connection.aclose()
@@ -0,0 +1,52 @@
1
+ # Copyright (c) 2026 Super Durable
2
+ # SPDX-License-Identifier: MIT
3
+ """Start a policy read through the static Google Docs connection."""
4
+
5
+ import argparse
6
+ import asyncio
7
+ import os
8
+ import tempfile
9
+
10
+ import dex
11
+ from dex_connectors.sdk.projectconfig import load_from_environment
12
+
13
+ from dex_connectors.google_docs import new_project_connection
14
+
15
+ from .flow import CONNECTION_NAME, PolicyReadFlow, PolicyReadRequest
16
+
17
+
18
+ async def start_policy_read(flow_id: str, document_id: str) -> str:
19
+ """Start one Flow for a Google Docs document ID."""
20
+ project = await load_from_environment()
21
+ connection = new_project_connection(project, CONNECTION_NAME)
22
+ try:
23
+ flow = PolicyReadFlow(connection)
24
+ registry = dex.Registry([flow], allow_async_handlers=True)
25
+ with tempfile.TemporaryDirectory(prefix="google-docs-python-start-blobs-") as directory:
26
+ cache = dex.open_blob_cache(dex.BlobCacheConfig(directory, 1 << 24))
27
+ try:
28
+ async with dex.AsyncClient(
29
+ registry, cache,
30
+ dex.ClientOptions(
31
+ server_address=os.environ.get("DEX_FLOW_SERVICE_ADDRESS", "localhost:8801")
32
+ ),
33
+ ) as client:
34
+ return await client.start_flow(flow, flow_id, PolicyReadRequest(document_id))
35
+ finally:
36
+ cache.close()
37
+ finally:
38
+ await connection.aclose()
39
+ await project.close()
40
+
41
+
42
+ def main() -> None:
43
+ """Parse a unique Flow ID and document ID."""
44
+ parser = argparse.ArgumentParser(description="Read a Google Doc through Dex")
45
+ parser.add_argument("flow_id")
46
+ parser.add_argument("document_id")
47
+ arguments = parser.parse_args()
48
+ print(asyncio.run(start_policy_read(arguments.flow_id, arguments.document_id)))
49
+
50
+
51
+ if __name__ == "__main__":
52
+ main()
@@ -0,0 +1,50 @@
1
+ # Copyright (c) 2026 Super Durable
2
+ # SPDX-License-Identifier: MIT
3
+ """Worker entrypoint for the Google Docs policy read Flow."""
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.google_docs import new_project_connection
14
+
15
+ from .flow import CONNECTION_NAME, PolicyReadFlow
16
+
17
+
18
+ async def run_worker() -> None:
19
+ """Load the connection and serve policy read executions."""
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([PolicyReadFlow(connection)], allow_async_handlers=True)
26
+ cache_directory = os.environ.get(
27
+ "DEX_BLOB_CACHE_DIR", str(Path(tempfile.gettempdir()) / "dex-google-docs-policy-blobs")
28
+ )
29
+ cache = dex.open_blob_cache(dex.BlobCacheConfig(cache_directory, 1 << 30))
30
+ worker = dex.AsyncWorker(
31
+ registry, cache,
32
+ dex.WorkerOptions(server_address=os.environ.get("DEX_FLOW_SERVICE_ADDRESS", "localhost:8801")),
33
+ )
34
+ async with worker:
35
+ await worker.start()
36
+ finally:
37
+ if connection is not None:
38
+ await connection.aclose()
39
+ if cache is not None:
40
+ cache.close()
41
+ await project.close()
42
+
43
+
44
+ def main() -> None:
45
+ """Run the Worker until stopped."""
46
+ asyncio.run(run_worker())
47
+
48
+
49
+ if __name__ == "__main__":
50
+ main()
@@ -0,0 +1,41 @@
1
+ [build-system]
2
+ requires = ["hatchling>=1.27"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [project]
6
+ name = "dex-connector-google-docs"
7
+ version = "0.1.0"
8
+ description = "Dex-native Google Docs connector"
9
+ readme = "README.md"
10
+ requires-python = ">=3.11"
11
+ license = "MIT"
12
+ license-files = ["LICENSE"]
13
+ dependencies = ["dex-connectors-sdk==0.7.0", "dex-python-sdk>=1.28.0", "httpx>=0.27"]
14
+
15
+ [project.urls]
16
+ Source = "https://github.com/superdurable/dex-connectors-library/tree/main/connectors/google/docs/python"
17
+
18
+ [dependency-groups]
19
+ dev = ["pytest>=8", "pytest-asyncio>=0.24", "mypy>=1.13", "ruff>=0.7", "PyYAML>=6", "types-PyYAML>=6"]
20
+
21
+ [tool.hatch.build.targets.wheel]
22
+ packages = ["src/dex_connectors"]
23
+
24
+ [tool.pytest.ini_options]
25
+ testpaths = ["tests"]
26
+ pythonpath = [".", "src"]
27
+ asyncio_mode = "auto"
28
+ asyncio_default_fixture_loop_scope = "function"
29
+
30
+ [tool.mypy]
31
+ python_version = "3.11"
32
+ strict = true
33
+ mypy_path = "src"
34
+ explicit_package_bases = true
35
+
36
+ [tool.ruff]
37
+ target-version = "py311"
38
+ line-length = 110
39
+
40
+ [tool.ruff.lint]
41
+ select = ["E", "F", "I", "UP", "B"]
@@ -0,0 +1,50 @@
1
+ # Copyright (c) 2026 Super Durable
2
+ # SPDX-License-Identifier: MIT
3
+ """Dex-native Google Docs provider operations and Step factories."""
4
+
5
+ from .client import Client, Config, Credentials
6
+ from .connection import Connection, new_connection, new_connection_with_operations, new_project_connection
7
+ from .models import (
8
+ AppendTextInput,
9
+ AppendTextOutput,
10
+ CreatedDocument,
11
+ CreateDocumentInput,
12
+ CreateDocumentOutput,
13
+ GetDocumentTextInput,
14
+ GetDocumentTextOutput,
15
+ PlaceholderReplacement,
16
+ PlaceholderReplacementResult,
17
+ ReplaceDocumentTextInput,
18
+ ReplaceDocumentTextOutput,
19
+ )
20
+ from .steps import (
21
+ new_append_text_step,
22
+ new_create_document_step,
23
+ new_get_document_text_step,
24
+ new_replace_document_text_step,
25
+ )
26
+
27
+ __all__ = [
28
+ "Client",
29
+ "Config",
30
+ "Credentials",
31
+ "Connection",
32
+ "new_connection",
33
+ "new_connection_with_operations",
34
+ "new_project_connection",
35
+ "AppendTextInput",
36
+ "AppendTextOutput",
37
+ "CreatedDocument",
38
+ "CreateDocumentInput",
39
+ "CreateDocumentOutput",
40
+ "GetDocumentTextInput",
41
+ "GetDocumentTextOutput",
42
+ "PlaceholderReplacement",
43
+ "PlaceholderReplacementResult",
44
+ "ReplaceDocumentTextInput",
45
+ "ReplaceDocumentTextOutput",
46
+ "new_append_text_step",
47
+ "new_create_document_step",
48
+ "new_get_document_text_step",
49
+ "new_replace_document_text_step",
50
+ ]
@@ -0,0 +1,2 @@
1
+ # Copyright (c) 2026 Super Durable
2
+ # SPDX-License-Identifier: MIT
@@ -0,0 +1,32 @@
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
+ docs_endpoint: str = "https://docs.googleapis.com"
14
+ drive_endpoint: str = "https://www.googleapis.com"
15
+ max_response_bytes: int = 8388608
16
+ max_text_bytes: int = 1048576
17
+
18
+ setattr(Config, '__module__', 'dex_connectors.google_docs.client')
19
+
20
+
21
+ @dataclass(frozen=True, slots=True)
22
+ class Credentials:
23
+
24
+ auth_method_id: str = "google-oauth"
25
+ oauth_client_id: str | None = None
26
+ oauth_client_secret: SecretString | None = None
27
+ access_token: SecretString | None = None
28
+ refresh_token: SecretString | None = None
29
+ service_account_key: SecretString | None = None
30
+ delegated_user: str | None = None
31
+
32
+ setattr(Credentials, '__module__', 'dex_connectors.google_docs.client')