routedef 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 (67) hide show
  1. routedef-0.1.0/.ci/max-loc-baseline.json +5 -0
  2. routedef-0.1.0/.ci/mutation-baseline.json +4 -0
  3. routedef-0.1.0/.ci/xenon-baseline.json +6 -0
  4. routedef-0.1.0/.github/workflows/ci.yml +120 -0
  5. routedef-0.1.0/.gitignore +14 -0
  6. routedef-0.1.0/.pre-commit-config.yaml +127 -0
  7. routedef-0.1.0/.secrets.baseline +106 -0
  8. routedef-0.1.0/LICENSE +21 -0
  9. routedef-0.1.0/LICENSES/MIT.txt +21 -0
  10. routedef-0.1.0/PKG-INFO +119 -0
  11. routedef-0.1.0/README.md +103 -0
  12. routedef-0.1.0/REUSE.toml +48 -0
  13. routedef-0.1.0/VERSION +1 -0
  14. routedef-0.1.0/docs/architecture.md +84 -0
  15. routedef-0.1.0/docs/diagrams/routedef-flow.puml +31 -0
  16. routedef-0.1.0/docs/diagrams/routedef-flow.svg +1 -0
  17. routedef-0.1.0/docs/diagrams/runtime-adapters.puml +50 -0
  18. routedef-0.1.0/docs/diagrams/runtime-adapters.svg +1 -0
  19. routedef-0.1.0/docs/migration.md +131 -0
  20. routedef-0.1.0/docs/superpowers/plans/2026-07-03-routedef-package-implementation.md +323 -0
  21. routedef-0.1.0/docs/superpowers/specs/2026-07-03-routedef-package-architecture-design.md +243 -0
  22. routedef-0.1.0/examples/cloudflare-worker/pyproject.toml +12 -0
  23. routedef-0.1.0/examples/cloudflare-worker/src/entry.py +44 -0
  24. routedef-0.1.0/examples/cloudflare-worker/wrangler.jsonc +11 -0
  25. routedef-0.1.0/pyproject.toml +128 -0
  26. routedef-0.1.0/scripts/check_build_install.py +87 -0
  27. routedef-0.1.0/scripts/check_cloudflare_worker.py +286 -0
  28. routedef-0.1.0/scripts/check_licenses.py +20 -0
  29. routedef-0.1.0/scripts/check_max_loc.py +91 -0
  30. routedef-0.1.0/scripts/check_spdx_headers.py +73 -0
  31. routedef-0.1.0/scripts/check_xenon.py +40 -0
  32. routedef-0.1.0/scripts/mutation_gate.py +54 -0
  33. routedef-0.1.0/scripts/retry_command.py +54 -0
  34. routedef-0.1.0/src/routedef/__init__.py +38 -0
  35. routedef-0.1.0/src/routedef/adapters/__init__.py +2 -0
  36. routedef-0.1.0/src/routedef/adapters/cloudflare.py +316 -0
  37. routedef-0.1.0/src/routedef/adapters/errors.py +17 -0
  38. routedef-0.1.0/src/routedef/adapters/fastapi.py +184 -0
  39. routedef-0.1.0/src/routedef/contracts.py +165 -0
  40. routedef-0.1.0/src/routedef/errors.py +10 -0
  41. routedef-0.1.0/src/routedef/headers.py +16 -0
  42. routedef-0.1.0/src/routedef/matching.py +97 -0
  43. routedef-0.1.0/src/routedef/py.typed +1 -0
  44. routedef-0.1.0/src/routedef/request.py +31 -0
  45. routedef-0.1.0/src/routedef/response.py +36 -0
  46. routedef-0.1.0/src/routedef/table.py +73 -0
  47. routedef-0.1.0/src/routedef/types.py +9 -0
  48. routedef-0.1.0/src/routedef/version.py +23 -0
  49. routedef-0.1.0/tests/cloudflare_fakes.py +136 -0
  50. routedef-0.1.0/tests/test_build_install_script.py +49 -0
  51. routedef-0.1.0/tests/test_cloudflare_adapter.py +459 -0
  52. routedef-0.1.0/tests/test_cloudflare_adapter_errors.py +113 -0
  53. routedef-0.1.0/tests/test_cloudflare_integration_script.py +122 -0
  54. routedef-0.1.0/tests/test_contracts.py +312 -0
  55. routedef-0.1.0/tests/test_fastapi_adapter.py +377 -0
  56. routedef-0.1.0/tests/test_headers.py +20 -0
  57. routedef-0.1.0/tests/test_logging_policy.py +44 -0
  58. routedef-0.1.0/tests/test_matching.py +125 -0
  59. routedef-0.1.0/tests/test_mutation_gate.py +65 -0
  60. routedef-0.1.0/tests/test_package_metadata.py +73 -0
  61. routedef-0.1.0/tests/test_quality_scripts.py +115 -0
  62. routedef-0.1.0/tests/test_request.py +36 -0
  63. routedef-0.1.0/tests/test_response.py +67 -0
  64. routedef-0.1.0/tests/test_retry_command.py +44 -0
  65. routedef-0.1.0/tests/test_table.py +112 -0
  66. routedef-0.1.0/tests/test_undef_style.py +329 -0
  67. routedef-0.1.0/tests/test_uwarp_style.py +101 -0
@@ -0,0 +1,5 @@
1
+ {
2
+ "max_lines": 500,
3
+ "roots": ["src", "tests", "scripts", "docs"],
4
+ "policy": "no counted project file may exceed max_lines"
5
+ }
@@ -0,0 +1,4 @@
1
+ {
2
+ "command": "uv run mutmut run && uv run mutmut results",
3
+ "allowed_survivors": []
4
+ }
@@ -0,0 +1,6 @@
1
+ {
2
+ "max_absolute": "C",
3
+ "max_modules": "B",
4
+ "max_average": "A",
5
+ "paths": ["src/routedef"]
6
+ }
@@ -0,0 +1,120 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: ["main", "feature/**"]
6
+ tags: ["v*"]
7
+ pull_request:
8
+ workflow_dispatch:
9
+
10
+ permissions:
11
+ contents: read
12
+
13
+ env:
14
+ UV_FROZEN: "0"
15
+ UV_LINK_MODE: copy
16
+
17
+ jobs:
18
+ quality:
19
+ name: Quality (${{ matrix.python-version }})
20
+ runs-on: ubuntu-latest
21
+ strategy:
22
+ fail-fast: false
23
+ matrix:
24
+ python-version: ["3.11", "3.12", "3.13"]
25
+ steps:
26
+ - name: Check out source
27
+ uses: actions/checkout@v7
28
+
29
+ - name: Prepare git metadata for act
30
+ if: ${{ env.ACT == 'true' }}
31
+ run: |
32
+ rm -rf .git
33
+ git init
34
+ git config user.email "act@example.invalid"
35
+ git config user.name "act"
36
+ git add .
37
+
38
+ - name: Install uv
39
+ run: |
40
+ curl -LsSf https://astral.sh/uv/install.sh | sh
41
+ echo "$HOME/.local/bin" >> "$GITHUB_PATH"
42
+
43
+ - name: Install Python
44
+ run: |
45
+ uv python install ${{ matrix.python-version }}
46
+
47
+ - name: Install dependencies
48
+ run: uv sync --python ${{ matrix.python-version }} --all-extras --dev
49
+
50
+ - name: Run pre-commit
51
+ run: uv run pre-commit run --all-files
52
+
53
+ - name: Run coverage gate
54
+ run: uv run python scripts/retry_command.py --exit-code 139 -- uv run pytest -q --cov=src/routedef --cov-branch --cov-report=term-missing --cov-fail-under=100
55
+
56
+ package:
57
+ name: Package
58
+ runs-on: ubuntu-latest
59
+ steps:
60
+ - name: Check out source
61
+ uses: actions/checkout@v7
62
+
63
+ - name: Install uv
64
+ run: |
65
+ curl -LsSf https://astral.sh/uv/install.sh | sh
66
+ echo "$HOME/.local/bin" >> "$GITHUB_PATH"
67
+
68
+ - name: Install Python
69
+ run: |
70
+ uv python install 3.13
71
+
72
+ - name: Install dependencies
73
+ run: uv sync --python 3.13 --all-extras --dev
74
+
75
+ - name: Build and smoke-test wheel
76
+ run: uv run python scripts/check_build_install.py
77
+
78
+ cloudflare-worker:
79
+ name: Cloudflare Worker
80
+ runs-on: ubuntu-latest
81
+ steps:
82
+ - name: Check out source
83
+ uses: actions/checkout@v7
84
+
85
+ - name: Install uv
86
+ run: |
87
+ curl -LsSf https://astral.sh/uv/install.sh | sh
88
+ echo "$HOME/.local/bin" >> "$GITHUB_PATH"
89
+
90
+ - name: Install Python
91
+ run: |
92
+ uv python install 3.13
93
+
94
+ - name: Install dependencies
95
+ run: uv sync --python 3.13 --all-extras --dev
96
+
97
+ - name: Run Cloudflare Python Worker integration
98
+ run: uv run python scripts/check_cloudflare_worker.py
99
+
100
+ mutation:
101
+ name: Mutation
102
+ runs-on: ubuntu-latest
103
+ steps:
104
+ - name: Check out source
105
+ uses: actions/checkout@v7
106
+
107
+ - name: Install uv
108
+ run: |
109
+ curl -LsSf https://astral.sh/uv/install.sh | sh
110
+ echo "$HOME/.local/bin" >> "$GITHUB_PATH"
111
+
112
+ - name: Install Python
113
+ run: |
114
+ uv python install 3.13
115
+
116
+ - name: Install dependencies
117
+ run: uv sync --python 3.13 --all-extras --dev
118
+
119
+ - name: Run mutation gate
120
+ run: uv run python scripts/mutation_gate.py
@@ -0,0 +1,14 @@
1
+ .coverage
2
+ .mypy_cache/
3
+ .mutmut-cache/
4
+ mutants/
5
+ .pytest_cache/
6
+ .ruff_cache/
7
+ .venv/
8
+ __pycache__/
9
+ dist/
10
+ htmlcov/
11
+ core
12
+ core.*
13
+ uv.lock
14
+ .worktrees/
@@ -0,0 +1,127 @@
1
+ repos:
2
+ - repo: local
3
+ hooks:
4
+ - id: detect-secrets
5
+ name: Detect secrets
6
+ entry: uv run python scripts/retry_command.py --exit-code 139 -- uv run detect-secrets-hook --baseline .secrets.baseline
7
+ language: system
8
+
9
+ - id: ruff-check
10
+ name: ruff check
11
+ entry: uv run ruff check --exit-non-zero-on-fix
12
+ language: system
13
+ types: [python]
14
+
15
+ - id: ruff-format
16
+ name: ruff format
17
+ entry: uv run ruff format --check
18
+ language: system
19
+ types: [python]
20
+
21
+ - id: codespell
22
+ name: codespell
23
+ entry: uv run python scripts/retry_command.py --exit-code 139 -- uv run codespell
24
+ language: system
25
+
26
+ - id: max-loc
27
+ name: python max loc
28
+ entry: uv run python scripts/check_max_loc.py --max-lines 500 --roots .
29
+ language: system
30
+ pass_filenames: false
31
+ always_run: true
32
+
33
+ - id: spdx-headers
34
+ name: Provide.io SPDX headers
35
+ entry: uv run python scripts/check_spdx_headers.py src tests scripts
36
+ language: system
37
+ pass_filenames: false
38
+ always_run: true
39
+ types: [python]
40
+
41
+ - id: licenses
42
+ name: license compliance
43
+ entry: uv run python scripts/check_licenses.py
44
+ language: system
45
+ pass_filenames: false
46
+ always_run: true
47
+
48
+ - id: mypy
49
+ name: mypy strict
50
+ entry: uv run mypy src tests
51
+ language: system
52
+ pass_filenames: false
53
+ always_run: true
54
+ types: [python]
55
+
56
+ - id: ty
57
+ name: ty check
58
+ entry: uv run ty check src tests
59
+ language: system
60
+ pass_filenames: false
61
+ always_run: true
62
+ types: [python]
63
+
64
+ - id: bandit
65
+ name: bandit
66
+ entry: uv run bandit -r src -ll
67
+ language: system
68
+ pass_filenames: false
69
+ always_run: true
70
+ types: [python]
71
+
72
+ - id: pytest
73
+ name: pytest
74
+ entry: uv run pytest -q
75
+ language: system
76
+ pass_filenames: false
77
+ always_run: true
78
+ types: [python]
79
+
80
+ - id: pip-audit
81
+ name: pip-audit vulnerability scan
82
+ entry: uv run python -m pip_audit
83
+ language: system
84
+ pass_filenames: false
85
+ always_run: true
86
+ types: [python]
87
+
88
+ - id: xenon
89
+ name: xenon complexity
90
+ entry: uv run python scripts/check_xenon.py --max-absolute C --max-modules B --max-average A --paths src/routedef
91
+ language: system
92
+ pass_filenames: false
93
+ always_run: true
94
+ types: [python]
95
+
96
+ - id: vulture
97
+ name: vulture dead code
98
+ entry: uv run vulture --min-confidence 80 src tests
99
+ language: system
100
+ pass_filenames: false
101
+ always_run: true
102
+ types: [python]
103
+
104
+ - id: mutation-sweep
105
+ name: mutmut gate (manual)
106
+ entry: uv run python scripts/mutation_gate.py
107
+ language: system
108
+ pass_filenames: false
109
+ always_run: true
110
+ stages: [manual]
111
+ types: [python]
112
+
113
+ - id: cloudflare-worker-integration
114
+ name: Cloudflare Python Worker integration (manual)
115
+ entry: uv run python scripts/check_cloudflare_worker.py
116
+ language: system
117
+ pass_filenames: false
118
+ always_run: true
119
+ stages: [manual]
120
+
121
+ - id: build-install-smoke
122
+ name: build and install smoke (manual)
123
+ entry: uv run python scripts/check_build_install.py
124
+ language: system
125
+ pass_filenames: false
126
+ always_run: true
127
+ stages: [manual]
@@ -0,0 +1,106 @@
1
+ {
2
+ "version": "1.5.0",
3
+ "plugins_used": [
4
+ {
5
+ "name": "ArtifactoryDetector"
6
+ },
7
+ {
8
+ "name": "AWSKeyDetector"
9
+ },
10
+ {
11
+ "name": "AzureStorageKeyDetector"
12
+ },
13
+ {
14
+ "name": "BasicAuthDetector"
15
+ },
16
+ {
17
+ "name": "CloudantDetector"
18
+ },
19
+ {
20
+ "name": "DiscordBotTokenDetector"
21
+ },
22
+ {
23
+ "name": "GitHubTokenDetector"
24
+ },
25
+ {
26
+ "name": "GitLabTokenDetector"
27
+ },
28
+ {
29
+ "name": "JwtTokenDetector"
30
+ },
31
+ {
32
+ "name": "KeywordDetector"
33
+ },
34
+ {
35
+ "name": "MailchimpDetector"
36
+ },
37
+ {
38
+ "name": "NpmDetector"
39
+ },
40
+ {
41
+ "name": "OpenAIDetector"
42
+ },
43
+ {
44
+ "name": "PrivateKeyDetector"
45
+ },
46
+ {
47
+ "name": "SendGridDetector"
48
+ },
49
+ {
50
+ "name": "SlackDetector"
51
+ },
52
+ {
53
+ "name": "SoftlayerDetector"
54
+ },
55
+ {
56
+ "name": "SquareOAuthDetector"
57
+ },
58
+ {
59
+ "name": "StripeDetector"
60
+ },
61
+ {
62
+ "name": "TelegramBotTokenDetector"
63
+ },
64
+ {
65
+ "name": "TwilioKeyDetector"
66
+ }
67
+ ],
68
+ "filters_used": [
69
+ {
70
+ "path": "detect_secrets.filters.allowlist.is_line_allowlisted"
71
+ },
72
+ {
73
+ "path": "detect_secrets.filters.common.is_ignored_due_to_verification_policies",
74
+ "min_level": 2
75
+ },
76
+ {
77
+ "path": "detect_secrets.filters.heuristic.is_indirect_reference"
78
+ },
79
+ {
80
+ "path": "detect_secrets.filters.heuristic.is_likely_id_string"
81
+ },
82
+ {
83
+ "path": "detect_secrets.filters.heuristic.is_lock_file"
84
+ },
85
+ {
86
+ "path": "detect_secrets.filters.heuristic.is_not_alphanumeric_string"
87
+ },
88
+ {
89
+ "path": "detect_secrets.filters.heuristic.is_potential_uuid"
90
+ },
91
+ {
92
+ "path": "detect_secrets.filters.heuristic.is_prefixed_with_dollar_sign"
93
+ },
94
+ {
95
+ "path": "detect_secrets.filters.heuristic.is_sequential_string"
96
+ },
97
+ {
98
+ "path": "detect_secrets.filters.heuristic.is_swagger_file"
99
+ },
100
+ {
101
+ "path": "detect_secrets.filters.heuristic.is_templated_secret"
102
+ }
103
+ ],
104
+ "results": {},
105
+ "generated_at": "2026-07-03T00:00:00Z"
106
+ }
routedef-0.1.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 provide.io llc
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
+ MIT License
2
+
3
+ Copyright (c) 2026 provide.io llc
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,119 @@
1
+ Metadata-Version: 2.4
2
+ Name: routedef
3
+ Version: 0.1.0
4
+ Summary: Route definition primitives for Python services.
5
+ Project-URL: Homepage, https://github.com/provide-io/routedef
6
+ Project-URL: Repository, https://github.com/provide-io/routedef
7
+ Project-URL: Documentation, https://github.com/provide-io/routedef/blob/main/docs/architecture.md
8
+ Project-URL: Issues, https://github.com/provide-io/routedef/issues
9
+ Author: provide.io llc
10
+ License-Expression: MIT
11
+ License-File: LICENSE
12
+ Requires-Python: >=3.11
13
+ Provides-Extra: fastapi
14
+ Requires-Dist: fastapi>=0.116.0; extra == 'fastapi'
15
+ Description-Content-Type: text/markdown
16
+
17
+ # RouteDef ๐Ÿงญ
18
+
19
+ Runtime-neutral route definitions for Python services.
20
+
21
+ `routedef` gives applications one route contract that can be mounted into multiple runtimes. The core package has
22
+ no FastAPI, Cloudflare, ASGI, auth, database, or application dependency. Runtime-specific code lives in adapters.
23
+
24
+ ## What It Provides โœ…
25
+
26
+ - `RouteDef`: method, path template, handler, and metadata.
27
+ - `RouteRequest`: canonical request object for handlers.
28
+ - `RouteResponse`: canonical response object for handlers.
29
+ - `RouteTable`: ordered method/path matching with `{path_param}` extraction.
30
+ - `build_fastapi_router`: FastAPI router integration.
31
+ - `CloudflareDispatcher`: direct Cloudflare Python Workers integration.
32
+
33
+ ## Why Use It ๐ŸŽฏ
34
+
35
+ Use `RouteDef` when you need the same route definitions to work across more than one Python runtime, especially
36
+ when migrating between framework-hosted APIs and Cloudflare Python Workers.
37
+
38
+ - One handler contract instead of per-runtime handler shapes.
39
+ - App-owned auth and authorization through metadata, auth providers, and enforcers.
40
+ - Dependency-free core package with optional runtime adapters.
41
+ - Testable route behavior without starting a web server.
42
+ - Migration-friendly wrappers for legacy split-argument handlers.
43
+
44
+ ## Why Not ๐Ÿšง
45
+
46
+ Do not use `RouteDef` as a full web framework, ORM, dependency injection container, auth library, or request
47
+ validation system. It intentionally does not own app policy, storage, schemas, background jobs, or runtime
48
+ lifecycle. If a service will only ever run in one framework and already has a stable route layer, the adapter
49
+ boundary may not be worth adding.
50
+
51
+ ## Architecture ๐Ÿ—๏ธ
52
+
53
+ ![routedef request flow](https://raw.githubusercontent.com/provide-io/routedef/main/docs/diagrams/routedef-flow.svg)
54
+
55
+ ![routedef package boundaries](https://raw.githubusercontent.com/provide-io/routedef/main/docs/diagrams/runtime-adapters.svg)
56
+
57
+ See [docs/architecture.md](https://github.com/provide-io/routedef/blob/main/docs/architecture.md) for package
58
+ boundaries and [docs/migration.md](https://github.com/provide-io/routedef/blob/main/docs/migration.md) for migration
59
+ examples covering undef-style roles, admin authorization callbacks, Taybols JWT auth, and uwarp split-argument
60
+ handlers.
61
+
62
+ ## Basic Usage ๐Ÿš€
63
+
64
+ ```python
65
+ from routedef import RouteDef, RouteRequest, RouteResponse, RouteTable
66
+
67
+
68
+ async def get_item(request: RouteRequest[None, dict[str, object]]) -> RouteResponse:
69
+ return RouteResponse.json({"id": request.path_params["id"]})
70
+
71
+
72
+ routes = RouteTable([RouteDef("GET", "/v1/items/{id}", get_item)])
73
+ ```
74
+
75
+ ## FastAPI
76
+
77
+ ```python
78
+ from fastapi import FastAPI
79
+ from routedef.adapters.fastapi import build_fastapi_router
80
+
81
+ app = FastAPI()
82
+ app.include_router(build_fastapi_router(routes))
83
+ ```
84
+
85
+ ## Cloudflare Python Workers
86
+
87
+ ```python
88
+ from routedef.adapters.cloudflare import CloudflareDispatcher
89
+ from workers import WorkerEntrypoint
90
+
91
+ dispatcher = CloudflareDispatcher(routes)
92
+
93
+
94
+ class Default(WorkerEntrypoint):
95
+ async def fetch(self, request):
96
+ return await dispatcher.dispatch(request)
97
+ ```
98
+
99
+ A real local Cloudflare fixture lives in
100
+ [examples/cloudflare-worker](https://github.com/provide-io/routedef/blob/main/examples/cloudflare-worker). Run it with:
101
+
102
+ ```bash
103
+ uv run python scripts/check_cloudflare_worker.py
104
+ ```
105
+
106
+ The integration script vendors the local `src/routedef` package into a temporary Python Worker project, runs
107
+ `pywrangler sync`, starts `wrangler@latest dev`, and probes routes over HTTP.
108
+
109
+ ## Quality Gates ๐Ÿงช
110
+
111
+ ```bash
112
+ uv run pre-commit run --all-files
113
+ uv run pytest -q --cov=src/routedef --cov-branch --cov-report=term-missing --cov-fail-under=100
114
+ uv run pre-commit run mutation-sweep --hook-stage manual
115
+ uv run pre-commit run cloudflare-worker-integration --hook-stage manual
116
+ ```
117
+
118
+ The project requires 100% branch coverage, strict typing, security/dead-code/complexity checks, REUSE compliance,
119
+ max-LOC checks, mutation testing, and a Cloudflare Worker runtime integration gate.
@@ -0,0 +1,103 @@
1
+ # RouteDef ๐Ÿงญ
2
+
3
+ Runtime-neutral route definitions for Python services.
4
+
5
+ `routedef` gives applications one route contract that can be mounted into multiple runtimes. The core package has
6
+ no FastAPI, Cloudflare, ASGI, auth, database, or application dependency. Runtime-specific code lives in adapters.
7
+
8
+ ## What It Provides โœ…
9
+
10
+ - `RouteDef`: method, path template, handler, and metadata.
11
+ - `RouteRequest`: canonical request object for handlers.
12
+ - `RouteResponse`: canonical response object for handlers.
13
+ - `RouteTable`: ordered method/path matching with `{path_param}` extraction.
14
+ - `build_fastapi_router`: FastAPI router integration.
15
+ - `CloudflareDispatcher`: direct Cloudflare Python Workers integration.
16
+
17
+ ## Why Use It ๐ŸŽฏ
18
+
19
+ Use `RouteDef` when you need the same route definitions to work across more than one Python runtime, especially
20
+ when migrating between framework-hosted APIs and Cloudflare Python Workers.
21
+
22
+ - One handler contract instead of per-runtime handler shapes.
23
+ - App-owned auth and authorization through metadata, auth providers, and enforcers.
24
+ - Dependency-free core package with optional runtime adapters.
25
+ - Testable route behavior without starting a web server.
26
+ - Migration-friendly wrappers for legacy split-argument handlers.
27
+
28
+ ## Why Not ๐Ÿšง
29
+
30
+ Do not use `RouteDef` as a full web framework, ORM, dependency injection container, auth library, or request
31
+ validation system. It intentionally does not own app policy, storage, schemas, background jobs, or runtime
32
+ lifecycle. If a service will only ever run in one framework and already has a stable route layer, the adapter
33
+ boundary may not be worth adding.
34
+
35
+ ## Architecture ๐Ÿ—๏ธ
36
+
37
+ ![routedef request flow](https://raw.githubusercontent.com/provide-io/routedef/main/docs/diagrams/routedef-flow.svg)
38
+
39
+ ![routedef package boundaries](https://raw.githubusercontent.com/provide-io/routedef/main/docs/diagrams/runtime-adapters.svg)
40
+
41
+ See [docs/architecture.md](https://github.com/provide-io/routedef/blob/main/docs/architecture.md) for package
42
+ boundaries and [docs/migration.md](https://github.com/provide-io/routedef/blob/main/docs/migration.md) for migration
43
+ examples covering undef-style roles, admin authorization callbacks, Taybols JWT auth, and uwarp split-argument
44
+ handlers.
45
+
46
+ ## Basic Usage ๐Ÿš€
47
+
48
+ ```python
49
+ from routedef import RouteDef, RouteRequest, RouteResponse, RouteTable
50
+
51
+
52
+ async def get_item(request: RouteRequest[None, dict[str, object]]) -> RouteResponse:
53
+ return RouteResponse.json({"id": request.path_params["id"]})
54
+
55
+
56
+ routes = RouteTable([RouteDef("GET", "/v1/items/{id}", get_item)])
57
+ ```
58
+
59
+ ## FastAPI
60
+
61
+ ```python
62
+ from fastapi import FastAPI
63
+ from routedef.adapters.fastapi import build_fastapi_router
64
+
65
+ app = FastAPI()
66
+ app.include_router(build_fastapi_router(routes))
67
+ ```
68
+
69
+ ## Cloudflare Python Workers
70
+
71
+ ```python
72
+ from routedef.adapters.cloudflare import CloudflareDispatcher
73
+ from workers import WorkerEntrypoint
74
+
75
+ dispatcher = CloudflareDispatcher(routes)
76
+
77
+
78
+ class Default(WorkerEntrypoint):
79
+ async def fetch(self, request):
80
+ return await dispatcher.dispatch(request)
81
+ ```
82
+
83
+ A real local Cloudflare fixture lives in
84
+ [examples/cloudflare-worker](https://github.com/provide-io/routedef/blob/main/examples/cloudflare-worker). Run it with:
85
+
86
+ ```bash
87
+ uv run python scripts/check_cloudflare_worker.py
88
+ ```
89
+
90
+ The integration script vendors the local `src/routedef` package into a temporary Python Worker project, runs
91
+ `pywrangler sync`, starts `wrangler@latest dev`, and probes routes over HTTP.
92
+
93
+ ## Quality Gates ๐Ÿงช
94
+
95
+ ```bash
96
+ uv run pre-commit run --all-files
97
+ uv run pytest -q --cov=src/routedef --cov-branch --cov-report=term-missing --cov-fail-under=100
98
+ uv run pre-commit run mutation-sweep --hook-stage manual
99
+ uv run pre-commit run cloudflare-worker-integration --hook-stage manual
100
+ ```
101
+
102
+ The project requires 100% branch coverage, strict typing, security/dead-code/complexity checks, REUSE compliance,
103
+ max-LOC checks, mutation testing, and a Cloudflare Worker runtime integration gate.