solvapay-python 0.7.2__tar.gz → 0.9.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 (188) hide show
  1. solvapay_python-0.9.0/.github/ISSUE_TEMPLATE/bug.yml +27 -0
  2. solvapay_python-0.9.0/.github/ISSUE_TEMPLATE/feature.yml +23 -0
  3. solvapay_python-0.9.0/.github/ISSUE_TEMPLATE/question.yml +14 -0
  4. solvapay_python-0.9.0/.github/PULL_REQUEST_TEMPLATE.md +15 -0
  5. solvapay_python-0.9.0/.github/dependabot.yml +18 -0
  6. solvapay_python-0.9.0/.github/workflows/ci.yml +53 -0
  7. solvapay_python-0.9.0/.github/workflows/contract.yml +22 -0
  8. solvapay_python-0.9.0/.github/workflows/docs.yml +21 -0
  9. {solvapay_python-0.7.2 → solvapay_python-0.9.0}/.gitignore +1 -0
  10. solvapay_python-0.9.0/CHANGELOG.md +121 -0
  11. solvapay_python-0.9.0/CODEOWNERS +1 -0
  12. solvapay_python-0.9.0/CODE_OF_CONDUCT.md +27 -0
  13. solvapay_python-0.9.0/CONTRIBUTING.md +71 -0
  14. solvapay_python-0.9.0/PKG-INFO +318 -0
  15. solvapay_python-0.9.0/README.md +282 -0
  16. solvapay_python-0.9.0/SECURITY.md +36 -0
  17. solvapay_python-0.9.0/SUPPORT.md +10 -0
  18. solvapay_python-0.9.0/assets/agent-marketplace.png +0 -0
  19. solvapay_python-0.9.0/changelog.d/README.md +35 -0
  20. solvapay_python-0.9.0/docs/architecture/layers.md +46 -0
  21. solvapay_python-0.9.0/docs/errors.md +50 -0
  22. solvapay_python-0.9.0/docs/guides/fastapi.md +53 -0
  23. solvapay_python-0.9.0/docs/guides/langchain.md +45 -0
  24. solvapay_python-0.9.0/docs/guides/mcp.md +50 -0
  25. solvapay_python-0.9.0/docs/idempotency.md +83 -0
  26. solvapay_python-0.9.0/docs/index.md +63 -0
  27. solvapay_python-0.9.0/docs/migration.md +49 -0
  28. solvapay_python-0.9.0/docs/reference/client.md +5 -0
  29. solvapay_python-0.9.0/docs/reference/exceptions.md +3 -0
  30. solvapay_python-0.9.0/docs/reference/models.md +3 -0
  31. solvapay_python-0.9.0/docs/reference/paywall.md +9 -0
  32. solvapay_python-0.9.0/docs/reference/webhooks.md +15 -0
  33. solvapay_python-0.9.0/docs/rfcs/0001-spending-policy.md +60 -0
  34. solvapay_python-0.9.0/docs/rfcs/0002-openapi-investigation.md +35 -0
  35. solvapay_python-0.9.0/docs/webhooks.md +79 -0
  36. solvapay_python-0.9.0/examples/marketplace/.gitignore +4 -0
  37. solvapay_python-0.9.0/examples/multi-framework-paywall/.env.example +3 -0
  38. solvapay_python-0.9.0/examples/multi-framework-paywall/.gitignore +4 -0
  39. solvapay_python-0.9.0/examples/multi-framework-paywall/README.md +52 -0
  40. solvapay_python-0.9.0/examples/multi-framework-paywall/agent_langchain.py +43 -0
  41. solvapay_python-0.9.0/examples/multi-framework-paywall/model.py +13 -0
  42. solvapay_python-0.9.0/examples/multi-framework-paywall/pyproject.toml +9 -0
  43. solvapay_python-0.9.0/examples/multi-framework-paywall/script_async.py +43 -0
  44. solvapay_python-0.9.0/examples/multi-framework-paywall/server_mcp.py +28 -0
  45. solvapay_python-0.9.0/examples/multi-framework-paywall/tool.py +36 -0
  46. solvapay_python-0.9.0/mkdocs.yml +44 -0
  47. {solvapay_python-0.7.2 → solvapay_python-0.9.0}/pyproject.toml +57 -2
  48. {solvapay_python-0.7.2 → solvapay_python-0.9.0}/src/solvapay/__init__.py +31 -1
  49. solvapay_python-0.9.0/src/solvapay/_async_client.py +329 -0
  50. solvapay_python-0.9.0/src/solvapay/_http.py +21 -0
  51. solvapay_python-0.9.0/src/solvapay/_stability.py +60 -0
  52. solvapay_python-0.9.0/src/solvapay/_transport/__init__.py +106 -0
  53. solvapay_python-0.9.0/src/solvapay/_transport/_recipe.py +63 -0
  54. solvapay_python-0.9.0/src/solvapay/_transport/httpx_transport.py +401 -0
  55. solvapay_python-0.9.0/src/solvapay/_transport/middleware.py +409 -0
  56. solvapay_python-0.9.0/src/solvapay/adapters/__init__.py +3 -0
  57. solvapay_python-0.9.0/src/solvapay/adapters/asgi.py +119 -0
  58. solvapay_python-0.9.0/src/solvapay/adapters/langchain.py +88 -0
  59. solvapay_python-0.9.0/src/solvapay/adapters/mcp.py +158 -0
  60. solvapay_python-0.9.0/src/solvapay/client.py +305 -0
  61. solvapay_python-0.9.0/src/solvapay/idempotency.py +37 -0
  62. solvapay_python-0.9.0/src/solvapay/langchain.py +15 -0
  63. solvapay_python-0.9.0/src/solvapay/operations/__init__.py +7 -0
  64. solvapay_python-0.9.0/src/solvapay/operations/_registry.py +117 -0
  65. solvapay_python-0.9.0/src/solvapay/operations/checkout.py +75 -0
  66. solvapay_python-0.9.0/src/solvapay/operations/customers.py +256 -0
  67. solvapay_python-0.9.0/src/solvapay/operations/limits.py +77 -0
  68. solvapay_python-0.9.0/src/solvapay/operations/merchant.py +71 -0
  69. solvapay_python-0.9.0/src/solvapay/operations/plans.py +167 -0
  70. solvapay_python-0.9.0/src/solvapay/operations/products.py +141 -0
  71. solvapay_python-0.9.0/src/solvapay/operations/purchases.py +103 -0
  72. solvapay_python-0.9.0/src/solvapay/operations/usage.py +75 -0
  73. solvapay_python-0.9.0/src/solvapay/paywall/__init__.py +32 -0
  74. solvapay_python-0.9.0/src/solvapay/paywall/core.py +152 -0
  75. solvapay_python-0.9.0/src/solvapay/paywall/decorators.py +126 -0
  76. solvapay_python-0.9.0/src/solvapay/paywall/meta.py +18 -0
  77. solvapay_python-0.9.0/src/solvapay/paywall/policy.py +14 -0
  78. solvapay_python-0.9.0/src/solvapay/paywall/resolvers.py +60 -0
  79. solvapay_python-0.9.0/src/solvapay/paywall/state.py +23 -0
  80. solvapay_python-0.9.0/src/solvapay/webhooks/__init__.py +43 -0
  81. solvapay_python-0.9.0/src/solvapay/webhooks/envelope.py +16 -0
  82. solvapay_python-0.9.0/src/solvapay/webhooks/pipeline.py +77 -0
  83. solvapay_python-0.9.0/src/solvapay/webhooks/replay.py +74 -0
  84. solvapay_python-0.9.0/src/solvapay/webhooks/rotation.py +36 -0
  85. solvapay_python-0.9.0/src/solvapay/webhooks/sign.py +37 -0
  86. solvapay_python-0.7.2/src/solvapay/webhooks.py → solvapay_python-0.9.0/src/solvapay/webhooks/verify.py +4 -22
  87. solvapay_python-0.9.0/tests/_stability/__init__.py +0 -0
  88. solvapay_python-0.9.0/tests/_stability/test_stable_returns_identity.py +75 -0
  89. solvapay_python-0.9.0/tests/_transport/__init__.py +0 -0
  90. solvapay_python-0.9.0/tests/_transport/test_aclose_cascade.py +100 -0
  91. solvapay_python-0.9.0/tests/_transport/test_error_wrapping.py +66 -0
  92. solvapay_python-0.9.0/tests/_transport/test_headers_case_insensitive.py +52 -0
  93. solvapay_python-0.9.0/tests/_transport/test_middleware_composition.py +51 -0
  94. solvapay_python-0.9.0/tests/_transport/test_protocol_conformance.py +46 -0
  95. solvapay_python-0.9.0/tests/_transport/test_recording_transport.py +68 -0
  96. solvapay_python-0.9.0/tests/_transport/test_retry_transport.py +78 -0
  97. solvapay_python-0.9.0/tests/adapters/__init__.py +0 -0
  98. solvapay_python-0.9.0/tests/adapters/test_asgi.py +91 -0
  99. solvapay_python-0.9.0/tests/adapters/test_langchain_protocol.py +99 -0
  100. solvapay_python-0.9.0/tests/adapters/test_mcp.py +165 -0
  101. solvapay_python-0.9.0/tests/contract/README.md +38 -0
  102. solvapay_python-0.9.0/tests/contract/__init__.py +0 -0
  103. solvapay_python-0.9.0/tests/contract/cassettes/.gitkeep +0 -0
  104. solvapay_python-0.9.0/tests/contract/test_contract_ops.py +61 -0
  105. solvapay_python-0.9.0/tests/operations/__init__.py +0 -0
  106. solvapay_python-0.9.0/tests/operations/test_namespace_api.py +59 -0
  107. solvapay_python-0.9.0/tests/operations/test_path_interpolation.py +54 -0
  108. solvapay_python-0.9.0/tests/operations/test_retry_safety_enum.py +57 -0
  109. solvapay_python-0.9.0/tests/paywall/__init__.py +0 -0
  110. solvapay_python-0.9.0/tests/paywall/test_checkout_mint_error_surfaces.py +52 -0
  111. solvapay_python-0.9.0/tests/paywall/test_payable_tool_meta.py +59 -0
  112. solvapay_python-0.9.0/tests/paywall/test_resolvers.py +47 -0
  113. solvapay_python-0.9.0/tests/paywall/test_split_classes.py +34 -0
  114. solvapay_python-0.9.0/tests/test_api_version.py +57 -0
  115. {solvapay_python-0.7.2 → solvapay_python-0.9.0}/tests/test_idempotency.py +33 -0
  116. {solvapay_python-0.7.2 → solvapay_python-0.9.0}/tests/test_invariants.py +2 -2
  117. {solvapay_python-0.7.2 → solvapay_python-0.9.0}/tests/test_langchain.py +21 -16
  118. {solvapay_python-0.7.2 → solvapay_python-0.9.0}/tests/test_paywall.py +5 -5
  119. {solvapay_python-0.7.2 → solvapay_python-0.9.0}/tests/test_paywall_state.py +42 -39
  120. solvapay_python-0.9.0/tests/webhooks/__init__.py +0 -0
  121. solvapay_python-0.9.0/tests/webhooks/test_async_cache.py +48 -0
  122. solvapay_python-0.9.0/tests/webhooks/test_clock_skew_vs_replay_ttl.py +58 -0
  123. solvapay_python-0.9.0/tests/webhooks/test_rotation.py +47 -0
  124. solvapay_python-0.9.0/tests/webhooks/test_seen_cache_atomic.py +54 -0
  125. solvapay_python-0.9.0/tests/webhooks/test_sign.py +37 -0
  126. solvapay_python-0.9.0/tests/webhooks/test_webhook_pipeline.py +66 -0
  127. solvapay_python-0.9.0/tools/api_baseline.json +82 -0
  128. solvapay_python-0.9.0/tools/api_diff.py +60 -0
  129. solvapay_python-0.9.0/tools/importlinter.cfg +42 -0
  130. solvapay_python-0.9.0/tools/lint_invariants.py +208 -0
  131. {solvapay_python-0.7.2 → solvapay_python-0.9.0}/uv.lock +1444 -120
  132. solvapay_python-0.7.2/.github/workflows/ci.yml +0 -24
  133. solvapay_python-0.7.2/CHANGELOG.md +0 -68
  134. solvapay_python-0.7.2/PKG-INFO +0 -357
  135. solvapay_python-0.7.2/README.md +0 -326
  136. solvapay_python-0.7.2/src/solvapay/_async_client.py +0 -387
  137. solvapay_python-0.7.2/src/solvapay/_http.py +0 -220
  138. solvapay_python-0.7.2/src/solvapay/client.py +0 -380
  139. solvapay_python-0.7.2/src/solvapay/idempotency.py +0 -16
  140. solvapay_python-0.7.2/src/solvapay/langchain.py +0 -67
  141. solvapay_python-0.7.2/src/solvapay/paywall.py +0 -153
  142. {solvapay_python-0.7.2 → solvapay_python-0.9.0}/.github/workflows/publish.yml +0 -0
  143. {solvapay_python-0.7.2 → solvapay_python-0.9.0}/.python-version +0 -0
  144. {solvapay_python-0.7.2 → solvapay_python-0.9.0}/LICENSE +0 -0
  145. {solvapay_python-0.7.2 → solvapay_python-0.9.0}/examples/fastmcp-paywall/.env.example +0 -0
  146. {solvapay_python-0.7.2 → solvapay_python-0.9.0}/examples/fastmcp-paywall/.gitignore +0 -0
  147. {solvapay_python-0.7.2 → solvapay_python-0.9.0}/examples/fastmcp-paywall/README.md +0 -0
  148. {solvapay_python-0.7.2 → solvapay_python-0.9.0}/examples/fastmcp-paywall/claim.py +0 -0
  149. {solvapay_python-0.7.2 → solvapay_python-0.9.0}/examples/fastmcp-paywall/pyproject.toml +0 -0
  150. {solvapay_python-0.7.2 → solvapay_python-0.9.0}/examples/fastmcp-paywall/server.py +0 -0
  151. {solvapay_python-0.7.2 → solvapay_python-0.9.0}/examples/fastmcp-paywall/uv.lock +0 -0
  152. {solvapay_python-0.7.2 → solvapay_python-0.9.0}/examples/langchain-paywall/.env.example +0 -0
  153. {solvapay_python-0.7.2 → solvapay_python-0.9.0}/examples/langchain-paywall/.gitignore +0 -0
  154. {solvapay_python-0.7.2 → solvapay_python-0.9.0}/examples/langchain-paywall/README.md +0 -0
  155. {solvapay_python-0.7.2 → solvapay_python-0.9.0}/examples/langchain-paywall/agent.py +0 -0
  156. {solvapay_python-0.7.2 → solvapay_python-0.9.0}/examples/langchain-paywall/pyproject.toml +0 -0
  157. {solvapay_python-0.7.2 → solvapay_python-0.9.0}/examples/marketplace/.env.example +0 -0
  158. {solvapay_python-0.7.2 → solvapay_python-0.9.0}/examples/marketplace/.streamlit/config.toml +0 -0
  159. {solvapay_python-0.7.2 → solvapay_python-0.9.0}/examples/marketplace/PLAN.md +0 -0
  160. {solvapay_python-0.7.2 → solvapay_python-0.9.0}/examples/marketplace/README.md +0 -0
  161. {solvapay_python-0.7.2 → solvapay_python-0.9.0}/examples/marketplace/agents.py +0 -0
  162. {solvapay_python-0.7.2 → solvapay_python-0.9.0}/examples/marketplace/app.py +0 -0
  163. {solvapay_python-0.7.2 → solvapay_python-0.9.0}/examples/marketplace/demo_customers.py +0 -0
  164. {solvapay_python-0.7.2 → solvapay_python-0.9.0}/examples/marketplace/requirements.txt +0 -0
  165. {solvapay_python-0.7.2 → solvapay_python-0.9.0}/examples/marketplace/sdk_gateway.py +0 -0
  166. {solvapay_python-0.7.2 → solvapay_python-0.9.0}/examples/marketplace/ui_components.py +0 -0
  167. {solvapay_python-0.7.2 → solvapay_python-0.9.0}/src/solvapay/_config.py +0 -0
  168. {solvapay_python-0.7.2 → solvapay_python-0.9.0}/src/solvapay/events.py +0 -0
  169. {solvapay_python-0.7.2 → solvapay_python-0.9.0}/src/solvapay/exceptions.py +0 -0
  170. {solvapay_python-0.7.2 → solvapay_python-0.9.0}/src/solvapay/fastapi.py +0 -0
  171. {solvapay_python-0.7.2 → solvapay_python-0.9.0}/src/solvapay/models.py +0 -0
  172. {solvapay_python-0.7.2 → solvapay_python-0.9.0}/src/solvapay/paywall_state.py +0 -0
  173. {solvapay_python-0.7.2 → solvapay_python-0.9.0}/src/solvapay/py.typed +0 -0
  174. {solvapay_python-0.7.2 → solvapay_python-0.9.0}/tests/__init__.py +0 -0
  175. {solvapay_python-0.7.2 → solvapay_python-0.9.0}/tests/conftest.py +0 -0
  176. {solvapay_python-0.7.2 → solvapay_python-0.9.0}/tests/test_admin.py +0 -0
  177. {solvapay_python-0.7.2 → solvapay_python-0.9.0}/tests/test_async_client.py +0 -0
  178. {solvapay_python-0.7.2 → solvapay_python-0.9.0}/tests/test_checkout.py +0 -0
  179. {solvapay_python-0.7.2 → solvapay_python-0.9.0}/tests/test_config.py +0 -0
  180. {solvapay_python-0.7.2 → solvapay_python-0.9.0}/tests/test_customer.py +0 -0
  181. {solvapay_python-0.7.2 → solvapay_python-0.9.0}/tests/test_errors.py +0 -0
  182. {solvapay_python-0.7.2 → solvapay_python-0.9.0}/tests/test_http.py +0 -0
  183. {solvapay_python-0.7.2 → solvapay_python-0.9.0}/tests/test_lifecycle.py +0 -0
  184. {solvapay_python-0.7.2 → solvapay_python-0.9.0}/tests/test_limits.py +0 -0
  185. {solvapay_python-0.7.2 → solvapay_python-0.9.0}/tests/test_packaging.py +0 -0
  186. {solvapay_python-0.7.2 → solvapay_python-0.9.0}/tests/test_redaction.py +0 -0
  187. {solvapay_python-0.7.2 → solvapay_python-0.9.0}/tests/test_webhook_events.py +0 -0
  188. {solvapay_python-0.7.2 → solvapay_python-0.9.0}/tests/test_webhooks.py +0 -0
@@ -0,0 +1,27 @@
1
+ name: Bug Report
2
+ description: Something broken in the SDK
3
+ labels: [bug]
4
+ body:
5
+ - type: markdown
6
+ attributes:
7
+ value: Please fill in the details below.
8
+ - type: input
9
+ id: version
10
+ attributes:
11
+ label: SDK version
12
+ placeholder: "0.8.0"
13
+ validations:
14
+ required: true
15
+ - type: textarea
16
+ id: description
17
+ attributes:
18
+ label: What happened?
19
+ description: What did you expect vs what actually happened?
20
+ validations:
21
+ required: true
22
+ - type: textarea
23
+ id: repro
24
+ attributes:
25
+ label: Minimal repro
26
+ description: Minimal Python snippet to reproduce
27
+ render: python
@@ -0,0 +1,23 @@
1
+ name: Feature Request
2
+ description: Suggest a new capability
3
+ labels: [enhancement]
4
+ body:
5
+ - type: textarea
6
+ id: problem
7
+ attributes:
8
+ label: What problem does this solve?
9
+ validations:
10
+ required: true
11
+ - type: textarea
12
+ id: proposal
13
+ attributes:
14
+ label: Proposed solution
15
+ validations:
16
+ required: true
17
+ - type: dropdown
18
+ id: priority
19
+ attributes:
20
+ label: Priority
21
+ options:
22
+ - Nice to have
23
+ - Blocking a use-case
@@ -0,0 +1,14 @@
1
+ name: Question
2
+ description: How do I...?
3
+ labels: [question]
4
+ body:
5
+ - type: textarea
6
+ id: question
7
+ attributes:
8
+ label: What are you trying to do?
9
+ validations:
10
+ required: true
11
+ - type: textarea
12
+ id: tried
13
+ attributes:
14
+ label: What have you tried?
@@ -0,0 +1,15 @@
1
+ ## What
2
+
3
+ <!-- Brief description of the change -->
4
+
5
+ ## Why
6
+
7
+ <!-- Problem it solves or feature it adds -->
8
+
9
+ ## Checklist
10
+
11
+ - [ ] Tests added / updated
12
+ - [ ] `CHANGELOG.md` entry added
13
+ - [ ] Layer DAG respected (`uv run lint-imports` passes)
14
+ - [ ] If new public exports: `tools/api_baseline.json` updated
15
+ - [ ] Docs updated (if public API changed)
@@ -0,0 +1,18 @@
1
+ version: 2
2
+ updates:
3
+ - package-ecosystem: pip
4
+ directory: /
5
+ schedule:
6
+ interval: weekly
7
+ open-pull-requests-limit: 5
8
+ labels:
9
+ - dependencies
10
+
11
+ - package-ecosystem: github-actions
12
+ directory: /
13
+ schedule:
14
+ interval: weekly
15
+ open-pull-requests-limit: 5
16
+ labels:
17
+ - dependencies
18
+ - ci
@@ -0,0 +1,53 @@
1
+ name: ci
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+
8
+ jobs:
9
+ test:
10
+ strategy:
11
+ matrix:
12
+ include:
13
+ # Linux — full Python matrix
14
+ - os: ubuntu-latest
15
+ python-version: "3.10"
16
+ - os: ubuntu-latest
17
+ python-version: "3.11"
18
+ - os: ubuntu-latest
19
+ python-version: "3.12"
20
+ # macOS — 3.12 only
21
+ - os: macos-latest
22
+ python-version: "3.12"
23
+ # Windows — 3.12 only
24
+ - os: windows-latest
25
+ python-version: "3.12"
26
+ runs-on: ${{ matrix.os }}
27
+ steps:
28
+ - uses: actions/checkout@v4
29
+ - uses: astral-sh/setup-uv@v3
30
+ with:
31
+ enable-cache: true
32
+ - name: Set Python ${{ matrix.python-version }}
33
+ run: uv python install ${{ matrix.python-version }}
34
+ - run: uv sync --all-extras --dev
35
+ - run: uv run ruff check src tests
36
+ - run: uv run ruff format --check src tests
37
+ - run: uv run mypy src
38
+ - run: uv run pytest -v
39
+ - run: uv run python tools/api_diff.py
40
+ - run: uv run lint-imports --config tools/importlinter.cfg
41
+ - run: uv run python tools/lint_invariants.py
42
+ - name: pip-audit
43
+ run: uv run pip-audit
44
+ - name: Check changelog fragment on PRs touching src/
45
+ if: github.event_name == 'pull_request'
46
+ run: |
47
+ changed=$(git diff --name-only origin/${{ github.base_ref }}...HEAD)
48
+ if echo "$changed" | grep -q "^src/"; then
49
+ if ! echo "$changed" | grep -q "^changelog.d/"; then
50
+ echo "ERROR: src/ modified without a changelog.d/ fragment. Add one — see changelog.d/README.md"
51
+ exit 1
52
+ fi
53
+ fi
@@ -0,0 +1,22 @@
1
+ name: contract
2
+
3
+ on:
4
+ schedule:
5
+ - cron: "0 2 * * *" # nightly at 02:00 UTC
6
+ workflow_dispatch:
7
+
8
+ jobs:
9
+ contract:
10
+ runs-on: ubuntu-latest
11
+ steps:
12
+ - uses: actions/checkout@v4
13
+ - uses: astral-sh/setup-uv@v3
14
+ with:
15
+ enable-cache: true
16
+ - run: uv sync --all-extras --dev
17
+ - name: Run contract tests
18
+ run: uv run pytest tests/contract/ -m contract -v
19
+ env:
20
+ SOLVAPAY_SANDBOX_KEY: ${{ secrets.SOLVAPAY_SANDBOX_KEY }}
21
+ SOLVAPAY_TEST_CUSTOMER_REF: ${{ secrets.SOLVAPAY_TEST_CUSTOMER_REF }}
22
+ SOLVAPAY_TEST_PRODUCT_REF: ${{ secrets.SOLVAPAY_TEST_PRODUCT_REF }}
@@ -0,0 +1,21 @@
1
+ name: docs
2
+
3
+ on:
4
+ push:
5
+ tags:
6
+ - "v*"
7
+
8
+ permissions:
9
+ contents: write
10
+
11
+ jobs:
12
+ deploy:
13
+ runs-on: ubuntu-latest
14
+ steps:
15
+ - uses: actions/checkout@v4
16
+ - uses: astral-sh/setup-uv@v3
17
+ with:
18
+ enable-cache: true
19
+ - run: uv sync --group docs
20
+ - name: Deploy to GitHub Pages
21
+ run: uv run mkdocs gh-deploy --force
@@ -12,3 +12,4 @@ htmlcov/
12
12
  .env
13
13
  .env.local
14
14
  *.egg
15
+ .DS_Store
@@ -0,0 +1,121 @@
1
+ # Changelog
2
+
3
+ ## 0.9.0 — 2026-05-23
4
+
5
+ Production polish + C1 adversarial-review closure. API-version pinning, idempotency TTL, webhook secret rotation, ASGI adapter, retry/recording transports, contract tests, lint automation, doc site, supply-chain hardening.
6
+
7
+ ### Added
8
+ - **API-version pinning**: `SolvaPay(api_version="2026-05-22")` and `AsyncSolvaPay(api_version=...)` send `Solvapay-Version` header. Default pinned to `"2026-05-22"`. `api_version=None` omits the header. (HLD V1.13)
9
+ - **Idempotency time-bucket encoding**: `from_payload(*parts, time_bucket="day"|"hour"|None)`. Default `"day"` appends UTC date so keys roll at midnight, bounding replay ambiguity past server TTL. (HLD V1.14)
10
+ - **Webhook secret rotation**: `MultiSecretVerifier` full implementation — tries primary then secondary on signature mismatch; both comparisons constant-time. (HLD V1.7)
11
+ - **`AsyncInMemorySeenEventCache`**: async replay-dedup cache using `asyncio.Lock` for async webhook pipelines. (HLD V1.7)
12
+ - **`sign_webhook(body, secret, *, timestamp)`**: public helper to produce a valid `sv-signature` header for testing and outbound webhook fanout.
13
+ - **ASGI webhook adapter** (`solvapay[asgi]`): `webhook_app(pipeline, on_event, path)` returns a raw ASGI app mountable in Starlette, FastAPI, Litestar, or BlackSheep. (HLD V1.10)
14
+ - **`RetryTransport`**: middleware that retries `APIConnectionError`, `APITimeoutError`, `APIServerError`, `RateLimitError` — exponential backoff with jitter, max 3 attempts. Consults `OpSpec.retry_safety`; refuses to retry `NEVER` ops. (HLD V1.4, `solvapay[retry]`)
15
+ - **`RecordingTransport`**: records `(RequestSpec, ResponseSpec)` pairs to JSON cassettes; replays on subsequent runs. Enables offline contract tests. (HLD V1.4)
16
+ - **Sandbox contract tests** (`tests/contract/`): one test per op against real sandbox via `RecordingTransport`. Nightly CI workflow (`contract.yml`).
17
+ - **Lint invariants** (`tools/lint_invariants.py`): AST checks for 10 gotchas (future annotations, `hmac.compare_digest`, no `logging.basicConfig`, no `asyncio.run()`, alias discipline, etc.). Run in CI on every push.
18
+ - **Towncrier changelog automation**: `changelog.d/` fragments, PR gate requiring a fragment when `src/` changes, `towncrier>=23` dev dep.
19
+ - **MkDocs Material doc site**: `mkdocs.yml` + `docs/` skeleton (Quickstart, Reference, Architecture, Guides, Errors, Idempotency, Webhooks, Migration). Deploys to GitHub Pages on tag. (HLD V1.12)
20
+ - **Dependabot**: weekly Python + GitHub Actions dependency updates (`.github/dependabot.yml`).
21
+ - **`pip-audit` in CI**: dependency CVE scan on every push.
22
+ - **CI matrix expanded**: Ubuntu 3.10/3.11/3.12 + macOS 3.12 + Windows 3.12. (HLD V1.15)
23
+ - **`ResourceWarning` on unclosed `AsyncSolvaPay`**: `__del__` emits `ResourceWarning` if client is not closed and event loop is still running.
24
+ - **OpenAPI investigation RFC**: `docs/rfcs/0002-openapi-investigation.md`.
25
+
26
+ ### Changed
27
+ - `pytest.ini_options.filterwarnings`: adds `ignore::DeprecationWarning:solvapay` so tests exercising deprecated flat-shim API do not fail on expected warnings.
28
+
29
+ ---
30
+
31
+ ## 0.8.0 — 2026-05-23
32
+
33
+ V1 architecture spine + AI-agent moat. 10 atomic commits establishing locked architecture invariants per HLD §V1.1–V1.19.
34
+
35
+ ### Added
36
+ - **Transport Protocol kernel** (`solvapay._transport`): `Transport`/`AsyncTransport` Protocol shapes, `RequestSpec`/`ResponseSpec` frozen dataclasses, case-insensitive `Headers`, canonical middleware stack (`Redacting` → `Logging` → `IdempotencyHeader` → `ContextPropagating`), `default_stack()` recipe.
37
+ - **Operations registry + resource-namespace API**: `OpSpec` + `RetrySafety` enum, `REGISTRY`, path interpolation with `urllib.parse.quote`. All clients gain eager namespace attrs: `sv.customers`, `sv.checkout`, `sv.limits`, `sv.purchases`, `sv.usage`, `sv.products`, `sv.plans`, `sv.merchant`.
38
+ - **Paywall package** (`solvapay.paywall`): `Paywall`/`AsyncPaywall` split with type-narrowed construction, `PaywallRequired.checkout_mint_error`, `PayableToolMeta(_meta_version=1)`, `KwargsResolver`/`PositionalResolver`/`PydanticBodyResolver`, `@require`/`@require_async`/`@payable_tool` decorators.
39
+ - **Webhook pipeline** (`solvapay.webhooks`): `WebhookPipeline` with two-knob config (`max_clock_skew_seconds`, `replay_ttl_seconds`), atomic `SeenEventCache.try_claim` (`threading.Lock`), `MultiSecretVerifier` interface, `WebhookEnvelope` dataclass.
40
+ - **`solvapay.adapters.mcp`** (optional `solvapay[mcp]`): `@payable_tool` decorator + four schema flavors (`payable_tool_mcp_schema`, `payable_tool_openai_function`, `payable_tool_anthropic_tool`, `payable_tool_langchain_args_schema`), `register_payable_tool_fastmcp`.
41
+ - **Stability manifest** (`solvapay._stability`): `stable(X)→X` identity decorator registers in `MANIFEST`; `experimental` emits once-per-process `RuntimeWarning`; `deprecated(removed_in=)`. CI gate: `tools/api_diff.py` fails on `@stable` symbol removal without prior `@deprecated`.
42
+ - **Import-linter DAG gate**: `tools/importlinter.cfg` (3 contracts), `docs/architecture/layers.md`. CI fails on layer violation.
43
+ - **LangChain adapter refactor** (`solvapay.adapters.langchain`): Protocol duck-typing — no hard `langchain_core` import at module level; absorbs 0.3→0.4 churn.
44
+ - **Multi-framework demo** (`examples/multi-framework-paywall/`): one `@payable_tool`-decorated function runs across FastMCP, LangChain, and raw async — "one tool, three runtimes, one paywall."
45
+ - **Governance scaffold**: `CODEOWNERS`, `SECURITY.md`, `CODE_OF_CONDUCT.md`, `SUPPORT.md`, `CONTRIBUTING.md`, GitHub issue templates, PR template, `docs/rfcs/0001-spending-policy.md`.
46
+
47
+ ### Changed
48
+ - **Flat methods deprecated**: `sv.ensure_customer()`, `sv.check_limits()`, etc. now emit `DeprecationWarning(stacklevel=2)` per call. Use `sv.customers.ensure()`, `sv.limits.check()`, etc. Flat shims removed in v2.0.
49
+ - **`langchain-core` upper bound**: `langchain-core>=0.3,<0.4` now enforced in both dev and optional deps.
50
+ - **`solvapay.langchain`** replaced by `solvapay.adapters.langchain`; old path is a deprecated shim.
51
+
52
+ ### Deprecated
53
+ - `SolvaPayAPIError` — use `APIError`. Alias fires `DeprecationWarning`; removed in v2.0.
54
+ - All flat client methods (`sv.ensure_customer`, `sv.check_limits`, etc.) — use resource-namespace API.
55
+
56
+ ## 0.7.2 — 2026-05-18
57
+
58
+ Bug fixes and documentation update.
59
+
60
+ ### Fixed
61
+ - **`paywall.require_async`**: `AsyncSolvaPay()` instantiated without a caller-supplied `client=` was not closed after the decorated function returned, leaking the underlying `httpx.AsyncClient` connection pool. Wrapped in `try/finally`; `await sv.aclose()` called when the decorator owns the client.
62
+ - **`examples/fastmcp-paywall/pyproject.toml`**: dependency used wrong PyPI dist name (`solvapay`) and a stale `@v0.3.0` pin. Updated to `solvapay-python>=0.7.2`.
63
+ - **`examples/langchain-paywall/pyproject.toml`**: same wrong dist name and stale `@v0.5.0` pin. Updated to `solvapay-python[langchain]>=0.7.2`.
64
+
65
+ ### Docs
66
+ - **README** updated to v0.7.1 surface: `paywall_state.gate()`, error hierarchy, idempotency keys, admin ops table, marketplace example, roadmap entries for v0.7.0 and v0.7.1.
67
+
68
+ ### Internal
69
+ - `tests/test_lifecycle.py` reformatted (ruff format compliance)
70
+
71
+ ## 0.7.1 — 2026-05-17
72
+
73
+ Payments-grade hardening: structured errors, idempotency keys, py.typed, structured logging.
74
+
75
+ ### Added
76
+ - **Structured error hierarchy** (`exceptions.py`): `APIError` base with `status_code`, `request_id`, `error_code`, `error_message`. Subclasses: `AuthenticationError` (401), `PermissionError` (403), `NotFoundError` (404), `RateLimitError` (429, adds `.retry_after`), `InvalidRequestError` (4xx), `APIServerError` (5xx), `APIConnectionError`, `APITimeoutError`. `SolvaPayAPIError` aliased to `APIError` for back-compat.
77
+ - **Idempotency keys** on all mutating ops: `create_checkout_session`, `ensure_customer`, `track_usage`, `cancel_purchase`, `reactivate_purchase`, `create_product`, `clone_product`, `create_plan` all accept `idempotency_key: str | None = None`. Header casing: `Idempotency-Key` (matches TS SDK).
78
+ - **`solvapay.idempotency.from_payload(*parts)`** — SHA256 of stable-serialized payload parts → 32-hex-char deterministic key.
79
+ - **PEP 561 `py.typed` marker** — downstream mypy users no longer see `Any` on `solvapay.*` imports.
80
+ - **Structured logging** at `solvapay.http` logger: INFO on success (method, path, status, request_id, duration_ms), WARNING on 4xx/5xx (adds body_excerpt ≤200 chars). Never calls `logging.basicConfig`. Optional `logger=` injection on `SolvaPay`/`AsyncSolvaPay` constructors for `loguru`/`structlog`.
81
+ - **Secret redaction**: `Authorization` header never appears in logs. Verified by `tests/test_redaction.py`.
82
+ - **pyproject classifiers**: `Development Status :: 4 - Beta`, `Framework :: AsyncIO`, `Topic :: Office/Business :: Financial`, `Typing :: Typed`.
83
+
84
+ ### Internal
85
+ - User-Agent bumped to `solvapay-python/0.7.1`
86
+ - 142 tests (up from 125), `mypy --strict` clean, `ruff` clean
87
+
88
+ ## 0.7.0 — 2026-05-17
89
+
90
+ Real-API alignment after testing against the SolvaPay sandbox revealed wire-format mismatches.
91
+
92
+ ### Fixed
93
+ - **`Customer.customer_ref`** now accepts `reference` (real API) in addition to `customerRef` via `validation_alias=AliasChoices(...)`.
94
+ - **`ensure_customer()`** reads `reference` from API response; falls back to `customerRef`. Raises if neither present.
95
+ - **`BalanceResponse`** rewritten: `credits`, `display_currency`, `credits_per_minor_unit`, `display_exchange_rate`; `balance` and `currency` kept as computed properties.
96
+
97
+ ### Added
98
+ - **`paywall_state.gate()`** — one-call enrichment helper (limits + checkout URL + plan via `get_customer`).
99
+ - **`paywall.require` / `require_async`**: auto-mints checkout URL when `LimitResponse.checkout_url is None`.
100
+ - **`examples/marketplace/`** — Streamlit demo with 4 paywalled AI agents (Google Gemini) against real SolvaPay sandbox.
101
+
102
+ ### Internal
103
+ - User-Agent `solvapay-python/0.7.0`. 125 tests (up from 121). `mypy --strict` clean.
104
+
105
+ ## 0.6.0
106
+ - Admin endpoints (products, plans, merchant config). GitHub Actions trusted-publish to PyPI.
107
+
108
+ ## 0.5.0
109
+ - `paywall_state` classifier (ACTIVATION_REQUIRED / TOPUP_REQUIRED / UPGRADE_REQUIRED). LangChain `monetize_tool`.
110
+
111
+ ## 0.4.0
112
+ - Full async client. 5 lifecycle operations. 13 typed webhook event classes.
113
+
114
+ ## 0.3.0
115
+ - FastMCP example: AI agent with two paywalled tools.
116
+
117
+ ## 0.2.0
118
+ - `@paywall.require` decorator. FastAPI webhook router.
119
+
120
+ ## 0.1.0
121
+ - Sync client, HMAC-SHA256 webhook verification, Pydantic v2 models, CI on 3 Python versions.
@@ -0,0 +1 @@
1
+ * @dhruv-sanan
@@ -0,0 +1,27 @@
1
+ # Contributor Covenant Code of Conduct
2
+
3
+ ## Our Pledge
4
+
5
+ We pledge to make participation in our community a harassment-free experience for everyone.
6
+
7
+ ## Our Standards
8
+
9
+ **Positive behavior:**
10
+ - Using welcoming and inclusive language
11
+ - Being respectful of differing viewpoints
12
+ - Gracefully accepting constructive criticism
13
+ - Focusing on what is best for the community
14
+
15
+ **Unacceptable behavior:**
16
+ - Harassment, trolling, or personal attacks
17
+ - Publishing others' private information without permission
18
+ - Other conduct which could reasonably be considered inappropriate
19
+
20
+ ## Enforcement
21
+
22
+ Community leaders may remove, edit, or reject contributions that violate this Code of Conduct.
23
+ Report issues to `dhruv.sanan@greyorange.com`.
24
+
25
+ ## Attribution
26
+
27
+ This Code of Conduct is adapted from the [Contributor Covenant](https://www.contributor-covenant.org), version 2.1.
@@ -0,0 +1,71 @@
1
+ # Contributing
2
+
3
+ ## Local development
4
+
5
+ ```bash
6
+ git clone https://github.com/dhruv-sanan/solvapay-python
7
+ cd solvapay-python
8
+ uv sync --all-extras --dev
9
+ ```
10
+
11
+ ## Running checks
12
+
13
+ ```bash
14
+ uv run ruff check src tests # lint
15
+ uv run ruff format --check src tests # format gate
16
+ uv run mypy src # type check
17
+ uv run pytest -v # tests
18
+ uv run python tools/api_diff.py # stability manifest gate
19
+ uv run lint-imports --config tools/importlinter.cfg # layer DAG gate
20
+ ```
21
+
22
+ ## Layer DAG rules
23
+
24
+ The SDK has a strict layer hierarchy — see [docs/architecture/layers.md](docs/architecture/layers.md).
25
+
26
+ **Hard rules:**
27
+ - `_transport` must not import `client`, `paywall`, `adapters`, or `operations`
28
+ - `operations` must not import `paywall` or `adapters`
29
+ - `client` must not import `adapters` or `experimental`
30
+
31
+ CI fails on violations via `import-linter`.
32
+
33
+ ## Changelog fragment (required)
34
+
35
+ Every PR that modifies `src/` must include a towncrier fragment in `changelog.d/`.
36
+
37
+ ```bash
38
+ # Create a fragment (replace 42 with your issue/PR number)
39
+ echo "Add RetryTransport middleware for automatic retry on transient errors." > changelog.d/42.feature
40
+ ```
41
+
42
+ See `changelog.d/README.md` for naming conventions and types.
43
+
44
+ PRs that touch `src/` without a `changelog.d/` entry will fail CI.
45
+
46
+ ## PR checklist
47
+
48
+ - [ ] Tests added for new behavior
49
+ - [ ] `changelog.d/<issue>.<type>` fragment added (required for `src/` changes)
50
+ - [ ] `docs/` updated if public API changed
51
+ - [ ] Layer DAG respected (`uv run lint-imports` passes)
52
+ - [ ] Stability manifest updated if new public exports added (`uv run python tools/api_diff.py`)
53
+
54
+ ## Commit style
55
+
56
+ [Conventional Commits](https://www.conventionalcommits.org/):
57
+
58
+ ```
59
+ feat: add AsyncPaywall class
60
+ fix(webhooks): set replay_ttl_seconds default correctly
61
+ refactor: extract _transport package
62
+ docs: update README with MCP quickstart
63
+ ```
64
+
65
+ ## Adding a new resource namespace
66
+
67
+ 1. Add `OpSpec` entries to `src/solvapay/operations/_registry.py`
68
+ 2. Create `src/solvapay/operations/<resource>.py` with sync + async methods
69
+ 3. Wire namespace attr in `SolvaPay.__init__` and `AsyncSolvaPay.__init__`
70
+ 4. Add deprecated flat shim in `client.py` / `_async_client.py`
71
+ 5. Tests in `tests/operations/`