fastapi-streams 0.0.1__tar.gz → 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 (128) hide show
  1. {fastapi_streams-0.0.1 → fastapi_streams-0.1.0}/.github/workflows/ci.yml +10 -5
  2. {fastapi_streams-0.0.1 → fastapi_streams-0.1.0}/.github/workflows/compatibility.yml +9 -5
  3. fastapi_streams-0.1.0/.github/workflows/release.yml +115 -0
  4. fastapi_streams-0.1.0/CHANGELOG.md +88 -0
  5. {fastapi_streams-0.0.1 → fastapi_streams-0.1.0}/PKG-INFO +8 -4
  6. {fastapi_streams-0.0.1 → fastapi_streams-0.1.0}/README.md +4 -0
  7. {fastapi_streams-0.0.1 → fastapi_streams-0.1.0}/docs/README.md +1 -0
  8. {fastapi_streams-0.0.1 → fastapi_streams-0.1.0}/docs/clients.md +52 -2
  9. {fastapi_streams-0.0.1 → fastapi_streams-0.1.0}/docs/codegen.md +38 -0
  10. {fastapi_streams-0.0.1 → fastapi_streams-0.1.0}/docs/development.md +1 -0
  11. fastapi_streams-0.1.0/docs/releasing.md +160 -0
  12. fastapi_streams-0.1.0/examples/agent_runs/errors.py +37 -0
  13. fastapi_streams-0.1.0/examples/agent_runs/errors.ts +44 -0
  14. fastapi_streams-0.1.0/examples/agent_runs/generated/agent-runs/api.ts +89 -0
  15. {fastapi_streams-0.0.1 → fastapi_streams-0.1.0}/examples/agent_runs/generated/index.ts +1 -1
  16. {fastapi_streams-0.0.1 → fastapi_streams-0.1.0}/examples/agent_runs/generated/transport/errors.ts +11 -0
  17. {fastapi_streams-0.0.1 → fastapi_streams-0.1.0}/examples/agent_runs/generated/types.ts +16 -16
  18. {fastapi_streams-0.0.1 → fastapi_streams-0.1.0}/examples/agent_runs/generated_python/agent_runs/api.py +34 -0
  19. {fastapi_streams-0.0.1 → fastapi_streams-0.1.0}/examples/agent_runs/generated_python/models.py +4 -0
  20. {fastapi_streams-0.0.1 → fastapi_streams-0.1.0}/fastapi_streams/__init__.py +1 -1
  21. fastapi_streams-0.1.0/fastapi_streams/codegen/diagnostics.py +79 -0
  22. fastapi_streams-0.1.0/fastapi_streams/codegen/documentation.py +59 -0
  23. {fastapi_streams-0.0.1 → fastapi_streams-0.1.0}/fastapi_streams/codegen/enums.py +4 -4
  24. {fastapi_streams-0.0.1 → fastapi_streams-0.1.0}/fastapi_streams/codegen/ir.py +10 -1
  25. {fastapi_streams-0.0.1 → fastapi_streams-0.1.0}/fastapi_streams/codegen/python.py +35 -5
  26. {fastapi_streams-0.0.1/tests/fixtures/generated/transport → fastapi_streams-0.1.0/fastapi_streams/codegen/templates}/errors.ts +11 -0
  27. {fastapi_streams-0.0.1 → fastapi_streams-0.1.0}/fastapi_streams/codegen/templates/python/api.py.j2 +5 -0
  28. {fastapi_streams-0.0.1 → fastapi_streams-0.1.0}/fastapi_streams/codegen/templates/typescript/api.ts.j2 +9 -1
  29. {fastapi_streams-0.0.1 → fastapi_streams-0.1.0}/fastapi_streams/codegen/typescript.py +23 -11
  30. {fastapi_streams-0.0.1 → fastapi_streams-0.1.0}/pyproject.toml +6 -5
  31. fastapi_streams-0.1.0/scripts/check_release.py +69 -0
  32. fastapi_streams-0.1.0/tests/codegen/test_diagnostics.py +64 -0
  33. fastapi_streams-0.1.0/tests/codegen/test_documentation.py +50 -0
  34. fastapi_streams-0.1.0/tests/codegen/test_error_contracts.py +149 -0
  35. fastapi_streams-0.1.0/tests/codegen/test_literal_fields.py +103 -0
  36. fastapi_streams-0.1.0/tests/fixtures/generated/fixtures/api.ts +51 -0
  37. {fastapi_streams-0.0.1 → fastapi_streams-0.1.0}/tests/fixtures/generated/index.ts +1 -1
  38. {fastapi_streams-0.0.1/fastapi_streams/codegen/templates → fastapi_streams-0.1.0/tests/fixtures/generated/transport}/errors.ts +11 -0
  39. {fastapi_streams-0.0.1 → fastapi_streams-0.1.0}/tests/fixtures/generated/types.ts +16 -16
  40. {fastapi_streams-0.0.1 → fastapi_streams-0.1.0}/tests/fixtures/generated_python/fixtures/api.py +17 -0
  41. {fastapi_streams-0.0.1 → fastapi_streams-0.1.0}/tests/fixtures/generated_python/models.py +2 -0
  42. fastapi_streams-0.1.0/tests/test_release.py +119 -0
  43. fastapi_streams-0.1.0/tests/typescript/errors.test.ts +69 -0
  44. {fastapi_streams-0.0.1 → fastapi_streams-0.1.0}/tests/typescript/tsconfig.json +1 -1
  45. fastapi_streams-0.0.1/examples/agent_runs/generated/agent-runs/api.ts +0 -49
  46. fastapi_streams-0.0.1/tests/fixtures/generated/fixtures/api.ts +0 -31
  47. fastapi_streams-0.0.1/uv.lock +0 -1218
  48. {fastapi_streams-0.0.1 → fastapi_streams-0.1.0}/.gitattributes +0 -0
  49. {fastapi_streams-0.0.1 → fastapi_streams-0.1.0}/.gitignore +0 -0
  50. {fastapi_streams-0.0.1 → fastapi_streams-0.1.0}/.pre-commit-config.yaml +0 -0
  51. {fastapi_streams-0.0.1 → fastapi_streams-0.1.0}/AGENTS.md +0 -0
  52. {fastapi_streams-0.0.1 → fastapi_streams-0.1.0}/LICENSE +0 -0
  53. {fastapi_streams-0.0.1 → fastapi_streams-0.1.0}/docs/architecture.md +0 -0
  54. {fastapi_streams-0.0.1 → fastapi_streams-0.1.0}/docs/quickstart.md +0 -0
  55. {fastapi_streams-0.0.1 → fastapi_streams-0.1.0}/examples/__init__.py +0 -0
  56. {fastapi_streams-0.0.1 → fastapi_streams-0.1.0}/examples/agent_runs/__init__.py +0 -0
  57. {fastapi_streams-0.0.1 → fastapi_streams-0.1.0}/examples/agent_runs/consume.py +0 -0
  58. {fastapi_streams-0.0.1 → fastapi_streams-0.1.0}/examples/agent_runs/consume.ts +0 -0
  59. {fastapi_streams-0.0.1 → fastapi_streams-0.1.0}/examples/agent_runs/generated/.fastapi-streams.json +0 -0
  60. {fastapi_streams-0.0.1 → fastapi_streams-0.1.0}/examples/agent_runs/generated/agent-runs/index.ts +0 -0
  61. {fastapi_streams-0.0.1 → fastapi_streams-0.1.0}/examples/agent_runs/generated/client.ts +0 -0
  62. {fastapi_streams-0.0.1 → fastapi_streams-0.1.0}/examples/agent_runs/generated/transport/sse.ts +0 -0
  63. {fastapi_streams-0.0.1 → fastapi_streams-0.1.0}/examples/agent_runs/generated_python/.fastapi-streams.json +0 -0
  64. {fastapi_streams-0.0.1 → fastapi_streams-0.1.0}/examples/agent_runs/generated_python/__init__.py +0 -0
  65. {fastapi_streams-0.0.1 → fastapi_streams-0.1.0}/examples/agent_runs/generated_python/agent_runs/__init__.py +0 -0
  66. {fastapi_streams-0.0.1 → fastapi_streams-0.1.0}/examples/agent_runs/generated_python/client.py +0 -0
  67. {fastapi_streams-0.0.1 → fastapi_streams-0.1.0}/examples/agent_runs/generated_python/py.typed +0 -0
  68. {fastapi_streams-0.0.1 → fastapi_streams-0.1.0}/examples/agent_runs/generated_python/runtime.py +0 -0
  69. {fastapi_streams-0.0.1 → fastapi_streams-0.1.0}/fastapi_streams/codegen/__init__.py +0 -0
  70. {fastapi_streams-0.0.1 → fastapi_streams-0.1.0}/fastapi_streams/codegen/cli.py +0 -0
  71. {fastapi_streams-0.0.1 → fastapi_streams-0.1.0}/fastapi_streams/codegen/names.py +0 -0
  72. {fastapi_streams-0.0.1 → fastapi_streams-0.1.0}/fastapi_streams/codegen/openapi.py +0 -0
  73. {fastapi_streams-0.0.1 → fastapi_streams-0.1.0}/fastapi_streams/codegen/schemas/LICENSE +0 -0
  74. {fastapi_streams-0.0.1 → fastapi_streams-0.1.0}/fastapi_streams/codegen/schemas/README.md +0 -0
  75. {fastapi_streams-0.0.1 → fastapi_streams-0.1.0}/fastapi_streams/codegen/schemas/openapi-3.2.json +0 -0
  76. {fastapi_streams-0.0.1 → fastapi_streams-0.1.0}/fastapi_streams/codegen/templates/python/client.py.j2 +0 -0
  77. {fastapi_streams-0.0.1 → fastapi_streams-0.1.0}/fastapi_streams/codegen/templates/python/runtime.py +0 -0
  78. {fastapi_streams-0.0.1 → fastapi_streams-0.1.0}/fastapi_streams/codegen/templates/sse.ts +0 -0
  79. {fastapi_streams-0.0.1 → fastapi_streams-0.1.0}/fastapi_streams/codegen/templates/typescript/client.ts.j2 +0 -0
  80. {fastapi_streams-0.0.1 → fastapi_streams-0.1.0}/fastapi_streams/codegen/templating.py +0 -0
  81. {fastapi_streams-0.0.1 → fastapi_streams-0.1.0}/fastapi_streams/codegen/writer.py +0 -0
  82. {fastapi_streams-0.0.1 → fastapi_streams-0.1.0}/fastapi_streams/py.typed +0 -0
  83. {fastapi_streams-0.0.1 → fastapi_streams-0.1.0}/fastapi_streams/router.py +0 -0
  84. {fastapi_streams-0.0.1 → fastapi_streams-0.1.0}/package-lock.json +0 -0
  85. {fastapi_streams-0.0.1 → fastapi_streams-0.1.0}/package.json +0 -0
  86. {fastapi_streams-0.0.1 → fastapi_streams-0.1.0}/scripts/check_package.py +0 -0
  87. {fastapi_streams-0.0.1 → fastapi_streams-0.1.0}/scripts/codegen.py +0 -0
  88. {fastapi_streams-0.0.1 → fastapi_streams-0.1.0}/scripts/smoke_package.py +0 -0
  89. {fastapi_streams-0.0.1 → fastapi_streams-0.1.0}/scripts/test_compat.py +0 -0
  90. {fastapi_streams-0.0.1 → fastapi_streams-0.1.0}/tests/__init__.py +0 -0
  91. {fastapi_streams-0.0.1 → fastapi_streams-0.1.0}/tests/codegen/helpers.py +0 -0
  92. {fastapi_streams-0.0.1 → fastapi_streams-0.1.0}/tests/codegen/test_additional_properties.py +0 -0
  93. {fastapi_streams-0.0.1 → fastapi_streams-0.1.0}/tests/codegen/test_codegen.py +0 -0
  94. {fastapi_streams-0.0.1 → fastapi_streams-0.1.0}/tests/codegen/test_contract_boundaries.py +0 -0
  95. {fastapi_streams-0.0.1 → fastapi_streams-0.1.0}/tests/codegen/test_discriminators.py +0 -0
  96. {fastapi_streams-0.0.1 → fastapi_streams-0.1.0}/tests/codegen/test_field_names.py +0 -0
  97. {fastapi_streams-0.0.1 → fastapi_streams-0.1.0}/tests/codegen/test_http_backends.py +0 -0
  98. {fastapi_streams-0.0.1 → fastapi_streams-0.1.0}/tests/codegen/test_intersections.py +0 -0
  99. {fastapi_streams-0.0.1 → fastapi_streams-0.1.0}/tests/codegen/test_nested_models.py +0 -0
  100. {fastapi_streams-0.0.1 → fastapi_streams-0.1.0}/tests/codegen/test_python_client.py +0 -0
  101. {fastapi_streams-0.0.1 → fastapi_streams-0.1.0}/tests/codegen/test_python_typing.py +0 -0
  102. {fastapi_streams-0.0.1 → fastapi_streams-0.1.0}/tests/codegen/test_required_properties.py +0 -0
  103. {fastapi_streams-0.0.1 → fastapi_streams-0.1.0}/tests/codegen/test_schema_matrix.py +0 -0
  104. {fastapi_streams-0.0.1 → fastapi_streams-0.1.0}/tests/contracts/test_openapi.py +0 -0
  105. {fastapi_streams-0.0.1 → fastapi_streams-0.1.0}/tests/fixtures/README.md +0 -0
  106. {fastapi_streams-0.0.1 → fastapi_streams-0.1.0}/tests/fixtures/__init__.py +0 -0
  107. {fastapi_streams-0.0.1 → fastapi_streams-0.1.0}/tests/fixtures/agent_runs.openapi.json +0 -0
  108. {fastapi_streams-0.0.1 → fastapi_streams-0.1.0}/tests/fixtures/compat-client.ts +0 -0
  109. {fastapi_streams-0.0.1 → fastapi_streams-0.1.0}/tests/fixtures/generated/.fastapi-streams.json +0 -0
  110. {fastapi_streams-0.0.1 → fastapi_streams-0.1.0}/tests/fixtures/generated/client.ts +0 -0
  111. {fastapi_streams-0.0.1 → fastapi_streams-0.1.0}/tests/fixtures/generated/fixtures/index.ts +0 -0
  112. {fastapi_streams-0.0.1 → fastapi_streams-0.1.0}/tests/fixtures/generated/transport/sse.ts +0 -0
  113. {fastapi_streams-0.0.1 → fastapi_streams-0.1.0}/tests/fixtures/generated_python/.fastapi-streams.json +0 -0
  114. {fastapi_streams-0.0.1 → fastapi_streams-0.1.0}/tests/fixtures/generated_python/__init__.py +0 -0
  115. {fastapi_streams-0.0.1 → fastapi_streams-0.1.0}/tests/fixtures/generated_python/client.py +0 -0
  116. {fastapi_streams-0.0.1 → fastapi_streams-0.1.0}/tests/fixtures/generated_python/fixtures/__init__.py +0 -0
  117. {fastapi_streams-0.0.1 → fastapi_streams-0.1.0}/tests/fixtures/generated_python/py.typed +0 -0
  118. {fastapi_streams-0.0.1 → fastapi_streams-0.1.0}/tests/fixtures/generated_python/runtime.py +0 -0
  119. {fastapi_streams-0.0.1 → fastapi_streams-0.1.0}/tests/fixtures/integration_app.py +0 -0
  120. {fastapi_streams-0.0.1 → fastapi_streams-0.1.0}/tests/fixtures/models.openapi.json +0 -0
  121. {fastapi_streams-0.0.1 → fastapi_streams-0.1.0}/tests/fixtures/models_app.py +0 -0
  122. {fastapi_streams-0.0.1 → fastapi_streams-0.1.0}/tests/integration/test_end_to_end.py +0 -0
  123. {fastapi_streams-0.0.1 → fastapi_streams-0.1.0}/tests/router/test_router.py +0 -0
  124. {fastapi_streams-0.0.1 → fastapi_streams-0.1.0}/tests/typescript/live-client.ts +0 -0
  125. {fastapi_streams-0.0.1 → fastapi_streams-0.1.0}/tests/typescript/models.test.ts +0 -0
  126. {fastapi_streams-0.0.1 → fastapi_streams-0.1.0}/tests/typescript/narrowing.ts +0 -0
  127. {fastapi_streams-0.0.1 → fastapi_streams-0.1.0}/tests/typescript/sse.test.ts +0 -0
  128. {fastapi_streams-0.0.1 → fastapi_streams-0.1.0}/tests/typing/client_usage.py +0 -0
@@ -2,7 +2,9 @@ name: CI
2
2
 
3
3
  on:
4
4
  push:
5
+ branches: ["**"]
5
6
  pull_request:
7
+ workflow_call:
6
8
 
7
9
  permissions:
8
10
  contents: read
@@ -16,15 +18,17 @@ jobs:
16
18
  matrix:
17
19
  python: ["3.12", "3.13", "3.14"]
18
20
  steps:
19
- - uses: actions/checkout@v4
20
- - uses: actions/setup-python@v5
21
+ - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
22
+ with:
23
+ persist-credentials: false
24
+ - uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5
21
25
  with:
22
26
  python-version: ${{ matrix.python }}
23
- - uses: actions/setup-node@v4
27
+ - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
24
28
  with:
25
29
  node-version: "24"
26
30
  cache: npm
27
- - uses: astral-sh/setup-uv@v6
31
+ - uses: astral-sh/setup-uv@d0cc045d04ccac9d8b7881df0226f9e82c39688e # v6
28
32
  with:
29
33
  version: "0.9.2"
30
34
  enable-cache: true
@@ -38,7 +42,7 @@ jobs:
38
42
  - run: npm run typecheck
39
43
  - run: npm run test:coverage
40
44
  - run: uv run pytest -q --cov --cov-report=term-missing --cov-report=xml:coverage-python.xml
41
- - uses: actions/upload-artifact@v4
45
+ - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
42
46
  if: always()
43
47
  with:
44
48
  name: coverage-python-${{ matrix.python }}
@@ -47,4 +51,5 @@ jobs:
47
51
  coverage-typescript.lcov
48
52
  - run: uv run python scripts/codegen.py --check
49
53
  - run: uv build
54
+ - run: uv run --frozen twine check --strict dist/*
50
55
  - run: uv run python scripts/check_package.py
@@ -2,7 +2,9 @@ name: Dependency compatibility
2
2
 
3
3
  on:
4
4
  push:
5
+ branches: ['**']
5
6
  pull_request:
7
+ workflow_call:
6
8
  workflow_dispatch:
7
9
  schedule:
8
10
  - cron: '17 7 * * 1'
@@ -22,22 +24,24 @@ jobs:
22
24
  python: ['3.12', '3.13', '3.14']
23
25
  dependencies: [lowest, latest]
24
26
  steps:
25
- - uses: actions/checkout@v4
26
- - uses: actions/setup-python@v5
27
+ - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
28
+ with:
29
+ persist-credentials: false
30
+ - uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5
27
31
  with:
28
32
  python-version: ${{ matrix.python }}
29
- - uses: actions/setup-node@v4
33
+ - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
30
34
  with:
31
35
  node-version: '24'
32
36
  cache: npm
33
- - uses: astral-sh/setup-uv@v6
37
+ - uses: astral-sh/setup-uv@d0cc045d04ccac9d8b7881df0226f9e82c39688e # v6
34
38
  with:
35
39
  version: '0.9.2'
36
40
  enable-cache: true
37
41
  - run: npm ci --ignore-scripts
38
42
  - name: Resolve dependencies and run native FastAPI and client integration tests
39
43
  run: python scripts/test_compat.py --python ${{ matrix.python }} --dependencies ${{ matrix.dependencies }}
40
- - uses: actions/upload-artifact@v4
44
+ - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
41
45
  if: always()
42
46
  with:
43
47
  name: compatibility-${{ matrix.os }}-${{ matrix.python }}-${{ matrix.dependencies }}
@@ -0,0 +1,115 @@
1
+ name: Release
2
+
3
+ on:
4
+ push:
5
+ tags: ['v*']
6
+
7
+ permissions:
8
+ contents: read
9
+
10
+ concurrency:
11
+ group: release-${{ github.ref }}
12
+ cancel-in-progress: false
13
+
14
+ jobs:
15
+ validate:
16
+ runs-on: ubuntu-latest
17
+ timeout-minutes: 5
18
+ outputs:
19
+ version: ${{ steps.version.outputs.version }}
20
+ prerelease: ${{ steps.version.outputs.prerelease }}
21
+ steps:
22
+ - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
23
+ with:
24
+ fetch-depth: 0
25
+ persist-credentials: false
26
+ - uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5
27
+ with:
28
+ python-version: '3.12'
29
+ - name: Validate tag, versions and main ancestry
30
+ id: version
31
+ env:
32
+ RELEASE_TAG: ${{ github.ref_name }}
33
+ run: python scripts/check_release.py "$RELEASE_TAG" >> "$GITHUB_OUTPUT"
34
+
35
+ ci:
36
+ needs: validate
37
+ uses: ./.github/workflows/ci.yml
38
+
39
+ compatibility:
40
+ needs: validate
41
+ uses: ./.github/workflows/compatibility.yml
42
+
43
+ build:
44
+ needs: [validate, ci, compatibility]
45
+ runs-on: ubuntu-latest
46
+ timeout-minutes: 15
47
+ steps:
48
+ - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
49
+ with:
50
+ persist-credentials: false
51
+ - uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5
52
+ with:
53
+ python-version: '3.12'
54
+ - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
55
+ with:
56
+ node-version: '24'
57
+ cache: npm
58
+ - uses: astral-sh/setup-uv@d0cc045d04ccac9d8b7881df0226f9e82c39688e # v6
59
+ with:
60
+ version: '0.9.2'
61
+ - run: uv sync --locked --all-extras
62
+ - run: npm ci --ignore-scripts
63
+ # Build the wheel from the sdist, including packaged templates and schemas.
64
+ - run: uv build --no-sources
65
+ - run: uv run --frozen twine check --strict dist/*
66
+ - run: uv run --frozen python scripts/check_package.py
67
+ - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
68
+ with:
69
+ name: release-distributions
70
+ path: |
71
+ dist/*.whl
72
+ dist/*.tar.gz
73
+ if-no-files-found: error
74
+ retention-days: 30
75
+
76
+ publish:
77
+ needs: build
78
+ runs-on: ubuntu-latest
79
+ timeout-minutes: 10
80
+ environment:
81
+ name: pypi
82
+ url: https://pypi.org/p/fastapi-streams
83
+ permissions:
84
+ id-token: write
85
+ steps:
86
+ - uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4
87
+ with:
88
+ name: release-distributions
89
+ path: dist/
90
+ - name: Publish to PyPI with Trusted Publishing and attestations
91
+ uses: pypa/gh-action-pypi-publish@dc37677b2e1c63e2034f94d8a5b11f265b73ba33 # release/v1
92
+ with:
93
+ attestations: true
94
+
95
+ github-release:
96
+ needs: [validate, publish]
97
+ runs-on: ubuntu-latest
98
+ timeout-minutes: 5
99
+ permissions:
100
+ contents: write
101
+ steps:
102
+ - uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4
103
+ with:
104
+ name: release-distributions
105
+ path: dist/
106
+ - name: Create GitHub Release with the published distributions
107
+ env:
108
+ GH_TOKEN: ${{ github.token }}
109
+ GH_REPO: ${{ github.repository }}
110
+ RELEASE_TAG: ${{ github.ref_name }}
111
+ PRERELEASE: ${{ needs.validate.outputs.prerelease }}
112
+ run: |
113
+ gh release create "$RELEASE_TAG" dist/* \
114
+ --verify-tag --generate-notes --title "$RELEASE_TAG" \
115
+ --prerelease="$PRERELEASE"
@@ -0,0 +1,88 @@
1
+ # Changelog
2
+
3
+ All notable changes and consumer upgrade steps are recorded here. Entries marked
4
+ unreleased describe prepared source versions that have not been published.
5
+
6
+ ## 0.1.0 - 2026-10-17
7
+
8
+ ### Added
9
+
10
+ - Generated TypeScript JSDoc and Python method docstrings include OpenAPI
11
+ summaries, descriptions, deprecation, and SDK-specific iteration, cancellation,
12
+ validation, and error behavior. Endpoint descriptions remain the source for
13
+ business guarantees such as retention or job lifetime after disconnect.
14
+ - `OptionalDiscriminatorWarning` identifies optional discriminator fields in
15
+ stream event unions, including nested and referenced events. Diagnostics name
16
+ the operation, route, model, and field; generation preserves schema requiredness.
17
+ - Explicit `OperationErrorBody` aliases in both SDKs distinguish declared HTTP
18
+ response bodies from thrown exceptions. Existing `OperationError` aliases remain
19
+ available; TypeScript marks them deprecated. Method documentation lists the
20
+ declared HTTP statuses and media types. Existing Python anonymous error-model
21
+ imports such as `OperationError0` retain their names.
22
+ - TypeScript `isHttpError(error, isDetails)` narrows `HttpError.details` only after
23
+ a caller-supplied type guard succeeds. It adds no runtime dependencies or assumed
24
+ problem format. HTTP status and operation provenance remain caller checks.
25
+ - Checked TypeScript and Python error-handling consumer examples, plus a
26
+ standalone FastAPI dependency/problem-response regression without an error
27
+ framework. Public generated error-alias name collisions now fail explicitly.
28
+
29
+ ### Changed
30
+
31
+ - Develop in `mathisarends/canon`; package source, documentation, and issue URLs
32
+ now point to the monorepo.
33
+ - Single-value string fields now use TypeScript/Python literals instead of
34
+ synthesizing a separate public constant object or `StrEnum` for every field.
35
+ Explicitly named enums, multi-value field enums, and shared event discriminator
36
+ enums remain available. TypeScript also omits unnecessary property quotes and
37
+ union parentheses while preserving intersection grouping and extra-field types.
38
+
39
+ ### Breaking generated-code changes
40
+
41
+ - Synthesized single-field constants such as `InvalidCredentialsProblemTitle`
42
+ and `InvalidCredentialsProblemType` are no longer exported. Replace usages like
43
+ `InvalidCredentialsProblemTitle.INVALID_CREDENTIALS` with the wire literal
44
+ `"Invalid credentials"`, then remove unused imports. Python singleton fields
45
+ now contain plain strings instead of generated `StrEnum` members; replace
46
+ identity checks with value comparisons. Shared discriminator values such as
47
+ `RunEventType.RUN_STARTED` and explicit schema enums are unchanged.
48
+ - Generated `OperationError`/`OperationErrorBody` names are reserved in both
49
+ SDKs. Python now reports collisions explicitly too. If a schema uses one of
50
+ these names, rename the colliding model or choose a distinct `operation_id`.
51
+
52
+ ### Upgrade from 0.0.1
53
+
54
+ 1. Update `fastapi-streams[codegen]` to `0.1.0`, using the same version for schema
55
+ export and both SDKs.
56
+ 2. Regenerate committed clients from the application's OpenAPI document. Existing
57
+ method names and call signatures are unchanged:
58
+
59
+ ```sh
60
+ uv run fastapi-streams schema --app your_app:app --output openapi.json
61
+ uv run fastapi-streams generate --schema openapi.json --language typescript --output generated/typescript
62
+ uv run fastapi-streams generate --schema openapi.json --language python --output generated/python
63
+ uv run fastapi-streams check --app your_app:app --schema openapi.json --language typescript --output generated/typescript
64
+ uv run fastapi-streams check --app your_app:app --schema openapi.json --language python --output generated/python
65
+ ```
66
+
67
+ Substitute the application's existing module and output paths. Preserve
68
+ `--python-http-client httpx2` on generation and checks if it is already used.
69
+ 3. Review optional discriminator warnings. For output-only Pydantic event models
70
+ whose defaults are always serialized, see the serialization configuration in
71
+ [the codegen guide](docs/codegen.md#event-discriminators). Do not make optional
72
+ request fields required merely because they have Python defaults. Add
73
+ endpoint-specific guarantees to OpenAPI descriptions. Export and regenerate
74
+ again after changing models or descriptions.
75
+ 4. Apply the single-field constant migration above if the application imported
76
+ these generated names. HTTP payloads, method names, and signatures are unchanged.
77
+ 5. Prefer `OperationErrorBody` over `OperationError` when referring to response
78
+ bodies. Keep caught errors unknown until checked; validate `HttpError.details`
79
+ with a body guard in TypeScript or Pydantic `TypeAdapter` in Python. See
80
+ [HTTP error contracts](docs/clients.md#http-error-contracts). Unexpected proxy
81
+ responses must continue through the generic `HttpError` fallback.
82
+ 6. Run the consuming project's TypeScript/Python type checks and stream tests.
83
+ Commit the exported schema and regenerated SDKs together with call-site updates.
84
+
85
+ ## 0.0.1
86
+
87
+ - Initial typed GET/POST JSON SSE routers, OpenAPI export, TypeScript and Python
88
+ generators, shared transports, and contract/client drift checks.
@@ -1,10 +1,10 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: fastapi-streams
3
- Version: 0.0.1
3
+ Version: 0.1.0
4
4
  Summary: Typed FastAPI streams with generated TypeScript and Python clients.
5
- Project-URL: Documentation, https://github.com/mathisarends/fastapi-streams/tree/main/docs
6
- Project-URL: Source, https://github.com/mathisarends/fastapi-streams
7
- Project-URL: Issues, https://github.com/mathisarends/fastapi-streams/issues
5
+ Project-URL: Documentation, https://github.com/mathisarends/canon/tree/main/packages/fastapi-streams/docs
6
+ Project-URL: Source, https://github.com/mathisarends/canon/tree/main/packages/fastapi-streams
7
+ Project-URL: Issues, https://github.com/mathisarends/canon/issues
8
8
  Author: Mathis Arends
9
9
  License-Expression: MIT
10
10
  License-File: LICENSE
@@ -224,6 +224,9 @@ and committed OpenAPI regression fixtures in `tests/fixtures/`. Verify all gener
224
224
 
225
225
  ## Documentation
226
226
 
227
+ See the [changelog and upgrade steps](CHANGELOG.md) when updating the library
228
+ and regenerating committed clients.
229
+
227
230
  | Guide | Topics |
228
231
  | --- | --- |
229
232
  | [Quickstart](docs/quickstart.md) | Setup, event models, and FastAPI integration. |
@@ -231,6 +234,7 @@ and committed OpenAPI regression fixtures in `tests/fixtures/`. Verify all gener
231
234
  | [Client usage](docs/clients.md) | Enums, authentication, cancellation, and errors. |
232
235
  | [Architecture](docs/architecture.md) | Native SSE, shared IR, templates, and transports. |
233
236
  | [Development](docs/development.md) | Tests, supported scope, and roadmap. |
237
+ | [Releasing](docs/releasing.md) | Tag-based releases and credential-free PyPI publishing. |
234
238
 
235
239
  v0.0.1 supports GET/POST JSON SSE streams. Ordinary REST endpoints stay in the
236
240
  contract for your existing REST SDK. See the [supported scope](docs/development.md#supported-scope-and-roadmap).
@@ -206,6 +206,9 @@ and committed OpenAPI regression fixtures in `tests/fixtures/`. Verify all gener
206
206
 
207
207
  ## Documentation
208
208
 
209
+ See the [changelog and upgrade steps](CHANGELOG.md) when updating the library
210
+ and regenerating committed clients.
211
+
209
212
  | Guide | Topics |
210
213
  | --- | --- |
211
214
  | [Quickstart](docs/quickstart.md) | Setup, event models, and FastAPI integration. |
@@ -213,6 +216,7 @@ and committed OpenAPI regression fixtures in `tests/fixtures/`. Verify all gener
213
216
  | [Client usage](docs/clients.md) | Enums, authentication, cancellation, and errors. |
214
217
  | [Architecture](docs/architecture.md) | Native SSE, shared IR, templates, and transports. |
215
218
  | [Development](docs/development.md) | Tests, supported scope, and roadmap. |
219
+ | [Releasing](docs/releasing.md) | Tag-based releases and credential-free PyPI publishing. |
216
220
 
217
221
  v0.0.1 supports GET/POST JSON SSE streams. Ordinary REST endpoints stay in the
218
222
  contract for your existing REST SDK. See the [supported scope](docs/development.md#supported-scope-and-roadmap).
@@ -9,6 +9,7 @@ TypeScript Fetch and Python HTTPX clients from the same definitions.
9
9
  | [Contracts and codegen](codegen.md) | Export OpenAPI, generate both clients, and detect drift in CI. |
10
10
  | [Client usage](clients.md) | Named event values, typed iteration, authentication, cancellation, and errors. |
11
11
  | [Development](development.md) | Local checks, test coverage, supported features, and roadmap. |
12
+ | [Releasing](releasing.md) | Tag-based releases, PyPI Trusted Publishing setup, and recovery. |
12
13
  | [Architecture](architecture.md) | Server integration, shared IR, generation, and transport boundaries. |
13
14
 
14
15
  Start with the [quickstart](quickstart.md), then use the
@@ -5,8 +5,10 @@
5
5
  ## Named values and typed iteration
6
6
 
7
7
  Discriminated unions produce an enum named after the union and discriminator:
8
- `RunEvent` + `type` becomes `RunEventType`. String enums and literal model fields
9
- also get named values. Python emits `StrEnum`; TypeScript emits an `as const`
8
+ `RunEvent` + `type` becomes `RunEventType`. Named string enums and multi-value
9
+ literal model fields also get named values. Single constant fields, such as
10
+ problem titles and URIs, remain inline literals. Python emits `StrEnum` for enums;
11
+ TypeScript emits an `as const`
10
12
  object plus a union type. Both retain exhaustive discriminator narrowing.
11
13
  Parameters use camelCase in TypeScript and snake_case in Python; wire aliases
12
14
  are preserved.
@@ -117,6 +119,54 @@ Pydantic; TypeScript provides static types and JSON decoding, with no runtime
117
119
  schema validator. Cancellation propagates normally; application error events
118
120
  remain ordinary members of the user-defined union.
119
121
 
122
+ ## HTTP error contracts
123
+
124
+ The SDK works with ordinary OpenAPI response declarations, including
125
+ `application/json`, `application/problem+json`, and other declared response media
126
+ types. No error registry or particular problem envelope is required. Declare
127
+ HTTP failures with FastAPI's `responses=`; put authentication, authorization,
128
+ and resource checks in dependencies so they can fail before the response starts.
129
+ Even generator statements before the first `yield` execute after response start.
130
+
131
+ Each operation with declared error schemas exports an `OperationErrorBody`
132
+ union: for example `StreamRunEventsErrorBody`. The earlier `OperationError`
133
+ name remains an alias for compatibility; it describes response bodies, not
134
+ the exceptions thrown by the SDK. Python imports these aliases from `models`;
135
+ TypeScript exports them from the SDK entrypoint.
136
+
137
+ Catch HTTP failures around **iteration**, since opening the request is lazy.
138
+ `HttpError.details` deliberately remains unvalidated: proxies and servers can
139
+ return unexpected JSON, plain text, HTML, incomplete bodies, or no body at all.
140
+ An operation's body union does not associate each variant with a status and does
141
+ not prove which operation produced an exception. Check the actual HTTP status
142
+ and validate the body before using application fields.
143
+
144
+ TypeScript provides `isHttpError(error, isDetails)`. Supply a type guard that
145
+ checks every field promised by its return type, or adapt an existing runtime
146
+ validator. The helper verifies the SDK exception class and invokes that guard;
147
+ it does not generate a schema validator or validate the HTTP status. A generic
148
+ type argument alone cannot replace the required guard. Failed guards leave the
149
+ original `HttpError` available for generic handling.
150
+
151
+ Python can validate `error.details` with `TypeAdapter(OperationErrorBody)` and
152
+ handle `ValidationError` as an unexpected response. Both approaches retain
153
+ the original status, response, and diagnostics. Schema unions with permissive
154
+ variants may accept a broad range of bodies; inspect the parsed variant before
155
+ using its fields. Existing limits on bounded HTTP diagnostics still apply.
156
+
157
+ The checked consumer examples show HTTP validation errors, fallback handling,
158
+ stream parsing/transport errors, and ordinary application error events:
159
+
160
+ - [TypeScript error handling](../examples/agent_runs/errors.ts), compiled with the
161
+ generated SDK under the repository's strict TypeScript configuration.
162
+ - [Python error handling](../examples/agent_runs/errors.py), checked by Pyright
163
+ with the generated models.
164
+
165
+ Caller cancellation continues to propagate. Neither SDK converts application
166
+ error events into exceptions or automatically retries a stream.
167
+
168
+ ## Python model fields
169
+
120
170
  Python uses `None` for omitted optional fields; `model_fields_set` distinguishes
121
171
  absence from explicit null. Explicit null is rejected for fields that may only
122
172
  be omitted. Requests exclude unset fields and serialize using wire aliases.
@@ -29,6 +29,12 @@ The generator extracts application data from
29
29
  reachable from their parameters, bodies, events and error responses are emitted.
30
30
  Operations use the first tag as their group, defaulting to `streams`.
31
31
 
32
+ Generated method documentation carries each operation's `summary`, `description`,
33
+ and `deprecated` marker alongside language-specific SDK behavior. Describe
34
+ replay, retention, and server job lifetime explicitly on your endpoint; the
35
+ generator does not infer these business guarantees. Python early exits should
36
+ use `contextlib.aclosing`; TypeScript `for await` cleanup closes its reader.
37
+
32
38
  TypeScript has no runtime dependencies and uses Fetch-compatible APIs. The
33
39
  example uses ES modules and is tested on Node 24. Generated Python packages
34
40
  require Python 3.12+, `httpx>=0.28` and `pydantic>=2.11.2` (`uv add httpx pydantic`).
@@ -57,6 +63,38 @@ REST operations remain available in the contract for an existing SDK generator
57
63
  such as Orval or HeyAPI. Keep REST and streaming SDKs in separate output
58
64
  directories. Reusing external generated model imports is a future feature.
59
65
 
66
+ ## Event discriminators
67
+
68
+ A Python default allows omitting a field when constructing a model. It does not
69
+ automatically make the field required in JSON Schema. The generator respects
70
+ `required` and warns with `OptionalDiscriminatorWarning` when a stream event
71
+ union uses an optional discriminator, including nested unions. An absent tag may
72
+ prevent variant selection; TypeScript's static types do not validate incoming JSON.
73
+
74
+ For **output-only** event models whose serializer always emits default fields,
75
+ configure the output schema to describe that behavior:
76
+
77
+ ```python
78
+ from pydantic import BaseModel, ConfigDict
79
+
80
+
81
+ class StreamEvent(BaseModel):
82
+ model_config = ConfigDict(
83
+ json_schema_mode_override="serialization",
84
+ json_schema_serialization_defaults_required=True,
85
+ )
86
+ ```
87
+
88
+ Inherit event variants from this model, or apply the configuration to an existing
89
+ output-only base. It marks all serialized default fields required, not only the
90
+ discriminator. Avoid applying it globally to shared request models: input and
91
+ output requiredness can differ. Alternatively, declare the tag without a default
92
+ and pass it explicitly. Regenerate the schema and clients after changing models.
93
+
94
+ Warnings are advisory and do not change fields or defaults. Python callers can
95
+ filter or promote this category using the standard `warnings` module; the category
96
+ is available from `fastapi_streams.codegen.diagnostics`.
97
+
60
98
  ## Check drift in CI
61
99
 
62
100
  ```sh
@@ -17,6 +17,7 @@ npm run test:coverage
17
17
  uv run pytest -q --cov --cov-report=term-missing --cov-report=xml:coverage-python.xml
18
18
  uv run python scripts/codegen.py --check
19
19
  uv build
20
+ uv run --frozen twine check --strict dist/*
20
21
  uv run python scripts/check_package.py
21
22
  ```
22
23
 
@@ -0,0 +1,160 @@
1
+ # Releasing
2
+
3
+ [Documentation](README.md) · [Project](../README.md)
4
+
5
+ A pushed Git tag is the release signal. The agent preparing a release only needs
6
+ permission to push the release tag to GitHub. GitHub Actions authenticates to PyPI
7
+ with OIDC (Trusted Publishing); no PyPI password or API token is stored in GitHub
8
+ or provided to an agent.
9
+
10
+ ## One-time maintainer setup (required before the first tag)
11
+
12
+ ### 1. Configure the GitHub environment
13
+
14
+ Open [Settings → Environments](https://github.com/mathisarends/fastapi-streams/settings/environments)
15
+ and create an environment named **`pypi`**.
16
+
17
+ - Under **Deployment branches and tags**, select **Selected branches and tags**
18
+ and add a **tag** rule for `v*`. Do not add a branch rule.
19
+ - Recommended: add a required reviewer if you want a human to approve each PyPI
20
+ upload after the agent pushes a tag. Enable prevention of self-review if your
21
+ approval policy requires another person. Without required reviewers, a valid
22
+ tag publishes automatically after validation and tests pass.
23
+ - Do not add a PyPI secret. The `publish` job requests `id-token: write`; the
24
+ separate GitHub Release job requests `contents: write` for its built-in
25
+ `GITHUB_TOKEN`. Repository or organization policies must allow these permissions
26
+ and the actions referenced in the workflows.
27
+
28
+ Create and protect this environment explicitly before publishing; a workflow can
29
+ otherwise create an environment without your intended protection rules.
30
+
31
+ ### 2. Register the PyPI Trusted Publisher
32
+
33
+ Sign in to PyPI with the account that owns (or will own) `fastapi-streams`.
34
+ For an existing project, open its
35
+ [Publishing settings](https://pypi.org/manage/project/fastapi-streams/settings/publishing/).
36
+ For a first publication, use
37
+ [Add a new pending publisher](https://pypi.org/manage/account/publishing/).
38
+
39
+ Select **GitHub** and enter these exact values:
40
+
41
+ | Field | Value |
42
+ | --- | --- |
43
+ | PyPI project name (pending publishers only) | `fastapi-streams` |
44
+ | Owner | `mathisarends` |
45
+ | Repository name | `fastapi-streams` |
46
+ | Workflow name | `release.yml` (filename only) |
47
+ | Environment name | `pypi` |
48
+
49
+ Confirm you control the package name. A pending publisher does not reserve a name;
50
+ the project is created on the first successful upload. PyPI and TestPyPI have
51
+ independent accounts and publisher registrations; this workflow publishes to
52
+ production PyPI only.
53
+
54
+ ### 3. Protect the release inputs
55
+
56
+ In [Settings → Rules → Rulesets](https://github.com/mathisarends/fastapi-streams/settings/rules),
57
+ protect `main` with pull request reviews and the existing CI and compatibility
58
+ checks. Review changes to the workflows, packaging configuration, and release
59
+ scripts as carefully as library changes.
60
+
61
+ Create a tag ruleset targeting `v*`. Restrict creation to authorized release
62
+ maintainers or a dedicated release GitHub App, and prevent updates and deletion.
63
+ Configure bypass access deliberately so the actor pushing a release tag can
64
+ create it. An agent that only prepares release PRs does not need tag creation
65
+ permission. An agent authorized to trigger releases does need that GitHub
66
+ permission, but still needs no PyPI credentials.
67
+
68
+ ## Prepare and trigger a release
69
+
70
+ 1. Resolve known release blockers and decide which changes belong in this version.
71
+ 2. Prepare a PR against `main`. Update `project.version` in `pyproject.toml` and
72
+ `__version__` in `fastapi_streams/__init__.py`, then run `uv lock` and commit the
73
+ updated `uv.lock`. Keep all three versions identical. For the first `0.0.1`
74
+ release these files already agree; a version bump is only needed for a new
75
+ version. Describe user-facing changes in the PR; GitHub uses merged PRs to
76
+ generate release notes.
77
+ 3. Merge after review and passing checks. Then tag the intended commit on `main`:
78
+
79
+ ```sh
80
+ git fetch origin main --tags
81
+ git switch main
82
+ git pull --ff-only origin main
83
+ python scripts/check_release.py v0.0.1
84
+ git tag -a v0.0.1 -m "Release v0.0.1"
85
+ git push origin v0.0.1
86
+ ```
87
+
88
+ Substitute the intended version everywhere. For an older release candidate
89
+ already on `main`, check out that exact commit before validating and tagging.
90
+ An annotated tag is recommended; do not move or reuse a published tag.
91
+
92
+ 4. Follow the [Release workflow](https://github.com/mathisarends/fastapi-streams/actions/workflows/release.yml)
93
+ and approve the `pypi` deployment if required reviewers are configured.
94
+ 5. Verify the version on [PyPI](https://pypi.org/project/fastapi-streams/) and the
95
+ [GitHub Releases page](https://github.com/mathisarends/fastapi-streams/releases).
96
+ Consumers can then install `fastapi-streams[codegen]==0.0.1` from PyPI.
97
+
98
+ Supported tags are `vX.Y.Z`, `vX.Y.ZaN`, `vX.Y.ZbN`, and `vX.Y.ZrcN`, using
99
+ canonical numbers without leading zeroes. Prereleases are published to PyPI and
100
+ marked as prereleases on GitHub. Development, local, and post-release versions
101
+ are deliberately rejected.
102
+
103
+ If a GitHub Actions agent pushes the tag, use an appropriately scoped GitHub App
104
+ installation token or personal access token. Events caused by the repository's
105
+ default `GITHUB_TOKEN` do not normally start another workflow. A locally running
106
+ agent can use its authorized GitHub Git credentials. Neither approach requires
107
+ PyPI credentials.
108
+
109
+ ## What the workflow guarantees
110
+
111
+ `.github/workflows/release.yml` runs these stages in order:
112
+
113
+ 1. **Validate:** reject unsupported tags, mismatched versions in the project,
114
+ module or lockfile, and commits outside `origin/main`. Validation reads the
115
+ module with Python's AST parser instead of importing package code.
116
+ 2. **Test:** call the existing CI workflow (Python 3.12–3.14, lint, types, Python
117
+ and TypeScript coverage, generated-file drift and wheel smoke tests) and the
118
+ complete Linux/Windows dependency compatibility matrix. These run against the
119
+ tag's exact commit and must all pass.
120
+ 3. **Build:** check the lockfile, build an sdist and a wheel from it, check metadata
121
+ and the README with Twine, then smoke-test this wheel in isolated environments
122
+ for the core install and each Python HTTP backend. Upload the distributions as
123
+ one immutable workflow artifact.
124
+ 4. **Publish:** download that artifact in a fresh job, pass the `pypi` environment
125
+ restrictions, and publish through PyPI Trusted Publishing with attestations.
126
+ This job has no source checkout, build steps, or stored credentials. Only this
127
+ job can request an OIDC token.
128
+ 5. **GitHub Release:** after PyPI succeeds, attach the same wheel and sdist to a
129
+ GitHub Release with automatically generated release notes. Only this job has
130
+ repository write permission.
131
+
132
+ Runs for the same tag are serialized without canceling an in-progress release.
133
+ All external actions in the release and its called workflows are pinned to full
134
+ commit SHAs; review and update those pins when adopting action updates.
135
+
136
+ ## Failures and retries
137
+
138
+ - Validation, test or build failure: nothing is published. Fix the release inputs
139
+ through a PR and use a new version/tag for the corrected candidate.
140
+ - Missing publisher or environment approval: complete the setup above and rerun
141
+ **failed jobs** on the original workflow run. This preserves the tested build
142
+ artifact. Artifacts are retained for 30 days.
143
+ - PyPI succeeded but GitHub Release creation failed: rerun only the failed GitHub
144
+ Release job. Do not rerun successful publishing jobs or rebuild the same PyPI
145
+ version. If a GitHub Release already exists after a partial failure, inspect it
146
+ and attach the original run's missing assets manually.
147
+ - Partial PyPI upload: inspect which files reached PyPI before retrying. The
148
+ workflow deliberately does not skip existing files; PyPI does not allow replacing
149
+ a published distribution. Publish a new version for changed package contents.
150
+
151
+ The setup is implemented here without creating a tag or publishing a package.
152
+ The first live upload also verifies your external PyPI and environment settings.
153
+
154
+ ## References
155
+
156
+ - [PyPI: publishing with a Trusted Publisher](https://docs.pypi.org/trusted-publishers/using-a-publisher/)
157
+ - [PyPI: creating a project with a pending publisher](https://docs.pypi.org/trusted-publishers/creating-a-project-through-oidc/)
158
+ - [PyPI: security model](https://docs.pypi.org/trusted-publishers/security-model/)
159
+ - [GitHub: OIDC with PyPI](https://docs.github.com/en/actions/how-tos/secure-your-work/security-harden-deployments/oidc-in-pypi)
160
+ - [GitHub: triggering workflows from workflows](https://docs.github.com/en/actions/how-tos/writing-workflows/choosing-when-your-workflow-runs/triggering-a-workflow)