livepeer-frameworks 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.
- livepeer_frameworks-0.1.0/.gitignore +189 -0
- livepeer_frameworks-0.1.0/PKG-INFO +75 -0
- livepeer_frameworks-0.1.0/README.md +44 -0
- livepeer_frameworks-0.1.0/pyproject.toml +88 -0
- livepeer_frameworks-0.1.0/src/livepeer_frameworks/__init__.py +81 -0
- livepeer_frameworks-0.1.0/src/livepeer_frameworks/_forward.py +97 -0
- livepeer_frameworks-0.1.0/src/livepeer_frameworks/_generated/__init__.py +3 -0
- livepeer_frameworks-0.1.0/src/livepeer_frameworks/_generated/events.py +67 -0
- livepeer_frameworks-0.1.0/src/livepeer_frameworks/_generated/graphql/__init__.py +673 -0
- livepeer_frameworks-0.1.0/src/livepeer_frameworks/_generated/graphql/abort_vod_upload.py +34 -0
- livepeer_frameworks-0.1.0/src/livepeer_frameworks/_generated/graphql/async_base_client.py +12 -0
- livepeer_frameworks-0.1.0/src/livepeer_frameworks/_generated/graphql/async_client.py +2567 -0
- livepeer_frameworks-0.1.0/src/livepeer_frameworks/_generated/graphql/base_model.py +19 -0
- livepeer_frameworks-0.1.0/src/livepeer_frameworks/_generated/graphql/client.py +2376 -0
- livepeer_frameworks-0.1.0/src/livepeer_frameworks/_generated/graphql/complete_vod_upload.py +47 -0
- livepeer_frameworks-0.1.0/src/livepeer_frameworks/_generated/graphql/create_clip.py +47 -0
- livepeer_frameworks-0.1.0/src/livepeer_frameworks/_generated/graphql/create_developer_token.py +44 -0
- livepeer_frameworks-0.1.0/src/livepeer_frameworks/_generated/graphql/create_push_target.py +14 -0
- livepeer_frameworks-0.1.0/src/livepeer_frameworks/_generated/graphql/create_signing_key.py +52 -0
- livepeer_frameworks-0.1.0/src/livepeer_frameworks/_generated/graphql/create_stream.py +41 -0
- livepeer_frameworks-0.1.0/src/livepeer_frameworks/_generated/graphql/create_stream_key.py +44 -0
- livepeer_frameworks-0.1.0/src/livepeer_frameworks/_generated/graphql/create_vod_upload.py +48 -0
- livepeer_frameworks-0.1.0/src/livepeer_frameworks/_generated/graphql/delete_clip.py +34 -0
- livepeer_frameworks-0.1.0/src/livepeer_frameworks/_generated/graphql/delete_dvr.py +34 -0
- livepeer_frameworks-0.1.0/src/livepeer_frameworks/_generated/graphql/delete_push_target.py +14 -0
- livepeer_frameworks-0.1.0/src/livepeer_frameworks/_generated/graphql/delete_stream.py +34 -0
- livepeer_frameworks-0.1.0/src/livepeer_frameworks/_generated/graphql/delete_stream_key.py +34 -0
- livepeer_frameworks-0.1.0/src/livepeer_frameworks/_generated/graphql/delete_vod_asset.py +34 -0
- livepeer_frameworks-0.1.0/src/livepeer_frameworks/_generated/graphql/enums.py +210 -0
- livepeer_frameworks-0.1.0/src/livepeer_frameworks/_generated/graphql/fragments.py +396 -0
- livepeer_frameworks-0.1.0/src/livepeer_frameworks/_generated/graphql/get_clip.py +12 -0
- livepeer_frameworks-0.1.0/src/livepeer_frameworks/_generated/graphql/get_dvr_chapter.py +26 -0
- livepeer_frameworks-0.1.0/src/livepeer_frameworks/_generated/graphql/get_signing_key.py +14 -0
- livepeer_frameworks-0.1.0/src/livepeer_frameworks/_generated/graphql/get_stream.py +12 -0
- livepeer_frameworks-0.1.0/src/livepeer_frameworks/_generated/graphql/get_tenant_usage.py +51 -0
- livepeer_frameworks-0.1.0/src/livepeer_frameworks/_generated/graphql/get_usage_aggregates.py +23 -0
- livepeer_frameworks-0.1.0/src/livepeer_frameworks/_generated/graphql/get_vod_asset.py +14 -0
- livepeer_frameworks-0.1.0/src/livepeer_frameworks/_generated/graphql/get_vod_upload_status.py +59 -0
- livepeer_frameworks-0.1.0/src/livepeer_frameworks/_generated/graphql/input_types.py +324 -0
- livepeer_frameworks-0.1.0/src/livepeer_frameworks/_generated/graphql/list_artifacts.py +23 -0
- livepeer_frameworks-0.1.0/src/livepeer_frameworks/_generated/graphql/list_developer_tokens.py +24 -0
- livepeer_frameworks-0.1.0/src/livepeer_frameworks/_generated/graphql/list_dvr_chapters.py +20 -0
- livepeer_frameworks-0.1.0/src/livepeer_frameworks/_generated/graphql/list_push_targets.py +20 -0
- livepeer_frameworks-0.1.0/src/livepeer_frameworks/_generated/graphql/list_signing_keys.py +22 -0
- livepeer_frameworks-0.1.0/src/livepeer_frameworks/_generated/graphql/list_stream_keys.py +22 -0
- livepeer_frameworks-0.1.0/src/livepeer_frameworks/_generated/graphql/list_streams.py +22 -0
- livepeer_frameworks-0.1.0/src/livepeer_frameworks/_generated/graphql/list_usage_records.py +40 -0
- livepeer_frameworks-0.1.0/src/livepeer_frameworks/_generated/graphql/refresh_stream_key.py +47 -0
- livepeer_frameworks-0.1.0/src/livepeer_frameworks/_generated/graphql/resolve_ingest_endpoint.py +33 -0
- livepeer_frameworks-0.1.0/src/livepeer_frameworks/_generated/graphql/resolve_viewer_endpoint.py +49 -0
- livepeer_frameworks-0.1.0/src/livepeer_frameworks/_generated/graphql/revoke_developer_token.py +34 -0
- livepeer_frameworks-0.1.0/src/livepeer_frameworks/_generated/graphql/revoke_signing_key.py +34 -0
- livepeer_frameworks-0.1.0/src/livepeer_frameworks/_generated/graphql/server_info.py +15 -0
- livepeer_frameworks-0.1.0/src/livepeer_frameworks/_generated/graphql/set_playback_policy.py +78 -0
- livepeer_frameworks-0.1.0/src/livepeer_frameworks/_generated/graphql/start_dvr.py +44 -0
- livepeer_frameworks-0.1.0/src/livepeer_frameworks/_generated/graphql/stop_dvr.py +34 -0
- livepeer_frameworks-0.1.0/src/livepeer_frameworks/_generated/graphql/sync_base_client.py +12 -0
- livepeer_frameworks-0.1.0/src/livepeer_frameworks/_generated/graphql/tenant_events.py +303 -0
- livepeer_frameworks-0.1.0/src/livepeer_frameworks/_generated/graphql/test_playback_access.py +48 -0
- livepeer_frameworks-0.1.0/src/livepeer_frameworks/_generated/graphql/update_push_target.py +14 -0
- livepeer_frameworks-0.1.0/src/livepeer_frameworks/_generated/graphql/update_stream.py +47 -0
- livepeer_frameworks-0.1.0/src/livepeer_frameworks/_generated/manifest.py +60 -0
- livepeer_frameworks-0.1.0/src/livepeer_frameworks/_generated/proto/__init__.py +0 -0
- livepeer_frameworks-0.1.0/src/livepeer_frameworks/_generated/proto/frameworks/__init__.py +0 -0
- livepeer_frameworks-0.1.0/src/livepeer_frameworks/_generated/proto/frameworks/events/__init__.py +106 -0
- livepeer_frameworks-0.1.0/src/livepeer_frameworks/_generated/proto/frameworks/events/public/__init__.py +0 -0
- livepeer_frameworks-0.1.0/src/livepeer_frameworks/_generated/proto/frameworks/events/public/v1/__init__.py +818 -0
- livepeer_frameworks-0.1.0/src/livepeer_frameworks/_generated/proto/google/__init__.py +0 -0
- livepeer_frameworks-0.1.0/src/livepeer_frameworks/_generated/proto/google/protobuf/__init__.py +2405 -0
- livepeer_frameworks-0.1.0/src/livepeer_frameworks/_generated/proto/message_pool.py +3 -0
- livepeer_frameworks-0.1.0/src/livepeer_frameworks/_generated/proto/py.typed +0 -0
- livepeer_frameworks-0.1.0/src/livepeer_frameworks/_server_info.py +106 -0
- livepeer_frameworks-0.1.0/src/livepeer_frameworks/_transport.py +799 -0
- livepeer_frameworks-0.1.0/src/livepeer_frameworks/client.py +28 -0
- livepeer_frameworks-0.1.0/src/livepeer_frameworks/errors.py +150 -0
- livepeer_frameworks-0.1.0/src/livepeer_frameworks/graphql.py +9 -0
- livepeer_frameworks-0.1.0/src/livepeer_frameworks/pagination.py +167 -0
- livepeer_frameworks-0.1.0/src/livepeer_frameworks/playback_token.py +110 -0
- livepeer_frameworks-0.1.0/src/livepeer_frameworks/py.typed +0 -0
- livepeer_frameworks-0.1.0/src/livepeer_frameworks/results.py +40 -0
- livepeer_frameworks-0.1.0/src/livepeer_frameworks/retry.py +57 -0
- livepeer_frameworks-0.1.0/src/livepeer_frameworks/upload.py +316 -0
- livepeer_frameworks-0.1.0/src/livepeer_frameworks/webhooks.py +141 -0
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
# Private runbook (environment-specific, do not commit)
|
|
2
|
+
/PRIVATE_RUNBOOK.md
|
|
3
|
+
/PLAN_*
|
|
4
|
+
/REPORT_*
|
|
5
|
+
|
|
6
|
+
# Operating System
|
|
7
|
+
.DS_Store
|
|
8
|
+
Thumbs.db
|
|
9
|
+
Desktop.ini
|
|
10
|
+
*~
|
|
11
|
+
.Trash*
|
|
12
|
+
.cache
|
|
13
|
+
.directory
|
|
14
|
+
ansible/.ansible/
|
|
15
|
+
|
|
16
|
+
# IDE & Editor
|
|
17
|
+
.vscode/*
|
|
18
|
+
!.vscode/settings.json
|
|
19
|
+
!.vscode/tasks.json
|
|
20
|
+
!.vscode/launch.json
|
|
21
|
+
!.vscode/extensions.json
|
|
22
|
+
.idea/
|
|
23
|
+
*.swp
|
|
24
|
+
*.swo
|
|
25
|
+
*.sublime-*
|
|
26
|
+
*~
|
|
27
|
+
\#*\#
|
|
28
|
+
|
|
29
|
+
# Node.js & Frontend
|
|
30
|
+
node_modules/
|
|
31
|
+
.pnpm-store/
|
|
32
|
+
dist/
|
|
33
|
+
build/
|
|
34
|
+
.svelte-kit/
|
|
35
|
+
.next/
|
|
36
|
+
.nuxt/
|
|
37
|
+
.output/
|
|
38
|
+
.vite/
|
|
39
|
+
website_marketing/.react-router/
|
|
40
|
+
coverage/
|
|
41
|
+
test-results/
|
|
42
|
+
*.log
|
|
43
|
+
.env*
|
|
44
|
+
!.env.example
|
|
45
|
+
|
|
46
|
+
# Claude Code per-project local state
|
|
47
|
+
.claude/
|
|
48
|
+
.playwright-cli/
|
|
49
|
+
|
|
50
|
+
# Houdini (GraphQL client)
|
|
51
|
+
$houdini/
|
|
52
|
+
.houdini/
|
|
53
|
+
|
|
54
|
+
# Go
|
|
55
|
+
*.exe
|
|
56
|
+
*.dll
|
|
57
|
+
*.so
|
|
58
|
+
*.dylib
|
|
59
|
+
*.test
|
|
60
|
+
*.out
|
|
61
|
+
go.work*
|
|
62
|
+
vendor/
|
|
63
|
+
|
|
64
|
+
# Android
|
|
65
|
+
.gradle/
|
|
66
|
+
build/
|
|
67
|
+
local.properties
|
|
68
|
+
.externalNativeBuild/
|
|
69
|
+
.cxx/
|
|
70
|
+
*.hprof
|
|
71
|
+
*.jks
|
|
72
|
+
*.keystore
|
|
73
|
+
|
|
74
|
+
# Infrastructure
|
|
75
|
+
*.db
|
|
76
|
+
*.sqlite*
|
|
77
|
+
*.dump
|
|
78
|
+
docker-compose.override.yml
|
|
79
|
+
.terraform*
|
|
80
|
+
*.tfstate*
|
|
81
|
+
|
|
82
|
+
# Temporary & Logs
|
|
83
|
+
**/tmp/
|
|
84
|
+
**/EXAMPLE*/
|
|
85
|
+
!npm_api/examples/
|
|
86
|
+
!npm_api/examples/**
|
|
87
|
+
!sdk_go/examples/
|
|
88
|
+
!sdk_go/examples/**
|
|
89
|
+
!sdk_python/examples/
|
|
90
|
+
!sdk_python/examples/**
|
|
91
|
+
**/temp/
|
|
92
|
+
**/logs/
|
|
93
|
+
*.log
|
|
94
|
+
*.pid
|
|
95
|
+
*.seed
|
|
96
|
+
bin
|
|
97
|
+
|
|
98
|
+
# Compiled Go binaries inside cmd/ directories
|
|
99
|
+
**/cmd/*/*
|
|
100
|
+
!**/cmd/*/*.go
|
|
101
|
+
!**/cmd/*/
|
|
102
|
+
|
|
103
|
+
# Go binaries from manual `go build` in service directories
|
|
104
|
+
api_balancing/foghorn
|
|
105
|
+
api_billing/purser
|
|
106
|
+
api_consultant/skipper
|
|
107
|
+
api_control/commodore
|
|
108
|
+
api_dns/navigator
|
|
109
|
+
api_firehose/decklog
|
|
110
|
+
api_forms/steward
|
|
111
|
+
api_gateway/bridge
|
|
112
|
+
api_analytics_ingest/periscope
|
|
113
|
+
api_analytics_query/periscope
|
|
114
|
+
api_mesh/privateer
|
|
115
|
+
api_realtime/signalman
|
|
116
|
+
api_sidecar/helmsman
|
|
117
|
+
api_tenants/quartermaster
|
|
118
|
+
api_ticketing/deckhand
|
|
119
|
+
api_assets/chandler
|
|
120
|
+
scripts/registry/registry
|
|
121
|
+
tools/release-plan/release-plan
|
|
122
|
+
|
|
123
|
+
# Security & Sensitive
|
|
124
|
+
*.pem
|
|
125
|
+
*.key
|
|
126
|
+
*.crt
|
|
127
|
+
*.cert
|
|
128
|
+
secrets.*
|
|
129
|
+
config/env/secrets.env
|
|
130
|
+
!config/env/secrets.env.example
|
|
131
|
+
scripts/env/.gocache/
|
|
132
|
+
scripts/env/env
|
|
133
|
+
**/.gocache/
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
# Backups & Archives
|
|
137
|
+
*.bak
|
|
138
|
+
*.backup
|
|
139
|
+
*.orig
|
|
140
|
+
*.zip
|
|
141
|
+
*.tar*
|
|
142
|
+
*.rar
|
|
143
|
+
*.7z
|
|
144
|
+
|
|
145
|
+
# Project Specific
|
|
146
|
+
mistserver.conf.bak
|
|
147
|
+
infrastructure/nginx/logs/
|
|
148
|
+
|
|
149
|
+
# Generated by local Mist/Helmsman demo runs. Tracked seed fixtures under this
|
|
150
|
+
# tree remain tracked; these rules keep fresh runtime outputs out of status.
|
|
151
|
+
infrastructure/demo-recordings/processing/
|
|
152
|
+
infrastructure/demo-recordings/trigger-wal/
|
|
153
|
+
infrastructure/demo-recordings/**/*.blocks/
|
|
154
|
+
infrastructure/demo-recordings/**/*.dtsh
|
|
155
|
+
infrastructure/demo-recordings/**/*.m3u8
|
|
156
|
+
infrastructure/demo-recordings/**/*.mkv
|
|
157
|
+
infrastructure/demo-recordings/**/*.ts
|
|
158
|
+
infrastructure/demo-recordings/**/*.pb
|
|
159
|
+
|
|
160
|
+
# Dead code analysis reports
|
|
161
|
+
reports/
|
|
162
|
+
|
|
163
|
+
# Agent discovery files (copied from docs/skills/ by prebuild)
|
|
164
|
+
website_application/static/SKILL.md
|
|
165
|
+
website_application/static/skill.json
|
|
166
|
+
website_application/static/heartbeat.md
|
|
167
|
+
website_application/static/llms.txt
|
|
168
|
+
website_application/static/robots.txt
|
|
169
|
+
website_application/static/.well-known/
|
|
170
|
+
website_marketing/public/SKILL.md
|
|
171
|
+
website_marketing/public/skill.json
|
|
172
|
+
website_marketing/public/heartbeat.md
|
|
173
|
+
website_marketing/public/llms.txt
|
|
174
|
+
website_marketing/public/robots.txt
|
|
175
|
+
website_marketing/public/.well-known/
|
|
176
|
+
website_docs/public/SKILL.md
|
|
177
|
+
website_docs/public/skill.json
|
|
178
|
+
website_docs/public/heartbeat.md
|
|
179
|
+
website_docs/public/llms.txt
|
|
180
|
+
website_docs/public/robots.txt
|
|
181
|
+
website_docs/public/.well-known/
|
|
182
|
+
.two-cell-pull-upstream/
|
|
183
|
+
|
|
184
|
+
# Python SDK dev environment and caches
|
|
185
|
+
sdk_python/.venv/
|
|
186
|
+
__pycache__/
|
|
187
|
+
.mypy_cache/
|
|
188
|
+
.pytest_cache/
|
|
189
|
+
*.egg-info/
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: livepeer-frameworks
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Typed client for the FrameWorks GraphQL API: operations, retries, pagination, typed errors, uploads, playback tokens, and webhooks
|
|
5
|
+
Project-URL: Documentation, https://logbook.frameworks.network/builders/sdks
|
|
6
|
+
Project-URL: Source, https://github.com/Livepeer-FrameWorks/monorepo/tree/master/sdk_python
|
|
7
|
+
Author: Livepeer FrameWorks
|
|
8
|
+
License-Expression: Unlicense
|
|
9
|
+
Keywords: frameworks,graphql,livepeer,sdk,streaming
|
|
10
|
+
Classifier: Framework :: AsyncIO
|
|
11
|
+
Classifier: Programming Language :: Python :: 3
|
|
12
|
+
Classifier: Typing :: Typed
|
|
13
|
+
Requires-Python: >=3.10
|
|
14
|
+
Requires-Dist: betterproto2==0.10.0
|
|
15
|
+
Requires-Dist: cryptography>=43
|
|
16
|
+
Requires-Dist: graphql-core<3.3,>=3.2
|
|
17
|
+
Requires-Dist: httpx<1,>=0.27
|
|
18
|
+
Requires-Dist: pydantic<3,>=2.7
|
|
19
|
+
Requires-Dist: standardwebhooks<2,>=1.1.0
|
|
20
|
+
Requires-Dist: websockets<18,>=13
|
|
21
|
+
Provides-Extra: dev
|
|
22
|
+
Requires-Dist: ariadne-codegen==0.19.0; extra == 'dev'
|
|
23
|
+
Requires-Dist: betterproto2-compiler==0.10.1; extra == 'dev'
|
|
24
|
+
Requires-Dist: build==1.6.1; extra == 'dev'
|
|
25
|
+
Requires-Dist: mypy==2.3.1; extra == 'dev'
|
|
26
|
+
Requires-Dist: pytest-asyncio==1.4.0; extra == 'dev'
|
|
27
|
+
Requires-Dist: pytest==9.1.1; extra == 'dev'
|
|
28
|
+
Requires-Dist: ruff==0.15.22; extra == 'dev'
|
|
29
|
+
Requires-Dist: twine==7.0.0; extra == 'dev'
|
|
30
|
+
Description-Content-Type: text/markdown
|
|
31
|
+
|
|
32
|
+
# livepeer-frameworks
|
|
33
|
+
|
|
34
|
+
Typed Python client for the [FrameWorks](https://frameworks.network) GraphQL API. It ships a sync
|
|
35
|
+
and an async client generated from FrameWorks' curated public operations, with pydantic models,
|
|
36
|
+
retries, pagination, typed errors, a VOD upload helper, playback token signing, and webhook
|
|
37
|
+
verification.
|
|
38
|
+
|
|
39
|
+
```sh
|
|
40
|
+
pip install livepeer-frameworks
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
```python
|
|
44
|
+
from livepeer_frameworks import FrameWorksClient, expect_result, paginate_relay
|
|
45
|
+
from livepeer_frameworks.graphql import ConnectionInput, CreateStreamCreateStreamStream, CreateStreamInput
|
|
46
|
+
|
|
47
|
+
with FrameWorksClient("https://bridge.example.com/graphql", token="YOUR_API_TOKEN") as fw:
|
|
48
|
+
created = fw.create_stream(input=CreateStreamInput(name="Studio A"))
|
|
49
|
+
# Returns the Stream member or raises ResultError for ValidationError/AuthError.
|
|
50
|
+
stream = expect_result(created.create_stream, CreateStreamCreateStreamStream)
|
|
51
|
+
print(stream.stream_key, stream.playback_id)
|
|
52
|
+
|
|
53
|
+
for s in paginate_relay(
|
|
54
|
+
lambda page: fw.list_streams(page=ConnectionInput.model_validate(page)).streams_connection
|
|
55
|
+
):
|
|
56
|
+
print(s.name)
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
The client reads no environment variables; pass the URL and token explicitly. Per-call options are
|
|
60
|
+
keyword arguments of the generated methods: `idempotency_key=` (sent as `Idempotency-Key`; paid
|
|
61
|
+
mutations settled with x402 need one) and `playback_token=` (sent as `X-Frameworks-Playback-JWT`).
|
|
62
|
+
|
|
63
|
+
Queries are retried on network errors and HTTP 408, 429, and 5xx. A mutation is retried only when
|
|
64
|
+
the request provably never reached the server: the connection could not be established, or the
|
|
65
|
+
gateway answered 429. It is never sent again after a timeout, a dropped connection, or a 5xx,
|
|
66
|
+
because the gateway does not deduplicate replayed mutations.
|
|
67
|
+
|
|
68
|
+
## Versions
|
|
69
|
+
|
|
70
|
+
The TypeScript, Go, and Python SDKs share one version. Until FrameWorks 1.0 the SDKs stay at 0.x,
|
|
71
|
+
and each minor line supports the FrameWorks releases listed for it; this line needs FrameWorks
|
|
72
|
+
v0.3.11 or later. Against an older stable release the client raises `ServerTooOldError` before
|
|
73
|
+
sending a call.
|
|
74
|
+
|
|
75
|
+
Documentation: <https://logbook.frameworks.network/builders/sdks>
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# livepeer-frameworks
|
|
2
|
+
|
|
3
|
+
Typed Python client for the [FrameWorks](https://frameworks.network) GraphQL API. It ships a sync
|
|
4
|
+
and an async client generated from FrameWorks' curated public operations, with pydantic models,
|
|
5
|
+
retries, pagination, typed errors, a VOD upload helper, playback token signing, and webhook
|
|
6
|
+
verification.
|
|
7
|
+
|
|
8
|
+
```sh
|
|
9
|
+
pip install livepeer-frameworks
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
```python
|
|
13
|
+
from livepeer_frameworks import FrameWorksClient, expect_result, paginate_relay
|
|
14
|
+
from livepeer_frameworks.graphql import ConnectionInput, CreateStreamCreateStreamStream, CreateStreamInput
|
|
15
|
+
|
|
16
|
+
with FrameWorksClient("https://bridge.example.com/graphql", token="YOUR_API_TOKEN") as fw:
|
|
17
|
+
created = fw.create_stream(input=CreateStreamInput(name="Studio A"))
|
|
18
|
+
# Returns the Stream member or raises ResultError for ValidationError/AuthError.
|
|
19
|
+
stream = expect_result(created.create_stream, CreateStreamCreateStreamStream)
|
|
20
|
+
print(stream.stream_key, stream.playback_id)
|
|
21
|
+
|
|
22
|
+
for s in paginate_relay(
|
|
23
|
+
lambda page: fw.list_streams(page=ConnectionInput.model_validate(page)).streams_connection
|
|
24
|
+
):
|
|
25
|
+
print(s.name)
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
The client reads no environment variables; pass the URL and token explicitly. Per-call options are
|
|
29
|
+
keyword arguments of the generated methods: `idempotency_key=` (sent as `Idempotency-Key`; paid
|
|
30
|
+
mutations settled with x402 need one) and `playback_token=` (sent as `X-Frameworks-Playback-JWT`).
|
|
31
|
+
|
|
32
|
+
Queries are retried on network errors and HTTP 408, 429, and 5xx. A mutation is retried only when
|
|
33
|
+
the request provably never reached the server: the connection could not be established, or the
|
|
34
|
+
gateway answered 429. It is never sent again after a timeout, a dropped connection, or a 5xx,
|
|
35
|
+
because the gateway does not deduplicate replayed mutations.
|
|
36
|
+
|
|
37
|
+
## Versions
|
|
38
|
+
|
|
39
|
+
The TypeScript, Go, and Python SDKs share one version. Until FrameWorks 1.0 the SDKs stay at 0.x,
|
|
40
|
+
and each minor line supports the FrameWorks releases listed for it; this line needs FrameWorks
|
|
41
|
+
v0.3.11 or later. Against an older stable release the client raises `ServerTooOldError` before
|
|
42
|
+
sending a call.
|
|
43
|
+
|
|
44
|
+
Documentation: <https://logbook.frameworks.network/builders/sdks>
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["hatchling>=1.27"]
|
|
3
|
+
build-backend = "hatchling.build"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "livepeer-frameworks"
|
|
7
|
+
dynamic = ["version"]
|
|
8
|
+
description = "Typed client for the FrameWorks GraphQL API: operations, retries, pagination, typed errors, uploads, playback tokens, and webhooks"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.10"
|
|
11
|
+
license = "Unlicense"
|
|
12
|
+
authors = [{ name = "Livepeer FrameWorks" }]
|
|
13
|
+
keywords = ["frameworks", "livepeer", "graphql", "streaming", "sdk"]
|
|
14
|
+
classifiers = [
|
|
15
|
+
"Programming Language :: Python :: 3",
|
|
16
|
+
"Typing :: Typed",
|
|
17
|
+
"Framework :: AsyncIO",
|
|
18
|
+
]
|
|
19
|
+
dependencies = [
|
|
20
|
+
"graphql-core>=3.2,<3.3",
|
|
21
|
+
"httpx>=0.27,<1",
|
|
22
|
+
"pydantic>=2.7,<3",
|
|
23
|
+
"websockets>=13,<18",
|
|
24
|
+
"standardwebhooks>=1.1.0,<2",
|
|
25
|
+
"betterproto2==0.10.0",
|
|
26
|
+
"cryptography>=43",
|
|
27
|
+
]
|
|
28
|
+
|
|
29
|
+
[project.optional-dependencies]
|
|
30
|
+
dev = [
|
|
31
|
+
"ariadne-codegen==0.19.0",
|
|
32
|
+
"betterproto2-compiler==0.10.1",
|
|
33
|
+
# Both generators format their output with ruff; pinned so the generated
|
|
34
|
+
# tree is byte-identical on every machine.
|
|
35
|
+
"ruff==0.15.22",
|
|
36
|
+
"mypy==2.3.1",
|
|
37
|
+
"pytest==9.1.1",
|
|
38
|
+
"pytest-asyncio==1.4.0",
|
|
39
|
+
# scripts/publish-packages.sh builds the distributions and uploads them.
|
|
40
|
+
"build==1.6.1",
|
|
41
|
+
"twine==7.0.0",
|
|
42
|
+
]
|
|
43
|
+
|
|
44
|
+
[project.urls]
|
|
45
|
+
Documentation = "https://logbook.frameworks.network/builders/sdks"
|
|
46
|
+
Source = "https://github.com/Livepeer-FrameWorks/monorepo/tree/master/sdk_python"
|
|
47
|
+
|
|
48
|
+
# The version is the shared SDK version, emitted from npm_api/package.json by
|
|
49
|
+
# scripts/sdkcontract (make graphql-sdk-py).
|
|
50
|
+
[tool.hatch.version]
|
|
51
|
+
path = "src/livepeer_frameworks/_generated/manifest.py"
|
|
52
|
+
pattern = 'SDK_VERSION: Final = "(?P<version>[^"]+)"'
|
|
53
|
+
|
|
54
|
+
[tool.hatch.build.targets.wheel]
|
|
55
|
+
packages = ["src/livepeer_frameworks"]
|
|
56
|
+
|
|
57
|
+
[tool.hatch.build.targets.sdist]
|
|
58
|
+
include = ["src/livepeer_frameworks", "README.md", "pyproject.toml"]
|
|
59
|
+
|
|
60
|
+
[tool.pytest.ini_options]
|
|
61
|
+
testpaths = ["tests"]
|
|
62
|
+
asyncio_mode = "auto"
|
|
63
|
+
asyncio_default_fixture_loop_scope = "function"
|
|
64
|
+
|
|
65
|
+
[tool.mypy]
|
|
66
|
+
python_version = "3.10"
|
|
67
|
+
strict = true
|
|
68
|
+
mypy_path = "src"
|
|
69
|
+
packages = ["livepeer_frameworks"]
|
|
70
|
+
plugins = ["pydantic.mypy"]
|
|
71
|
+
|
|
72
|
+
# The GraphQL client and models are checked with the defaults; they are
|
|
73
|
+
# fully annotated but ariadne-codegen emits patterns strict mode rejects.
|
|
74
|
+
[[tool.mypy.overrides]]
|
|
75
|
+
module = ["livepeer_frameworks._generated.graphql.*"]
|
|
76
|
+
disallow_any_generics = false
|
|
77
|
+
warn_return_any = false
|
|
78
|
+
disallow_untyped_calls = false
|
|
79
|
+
|
|
80
|
+
# betterproto2 output is third-party generated code (google.protobuf and the
|
|
81
|
+
# event messages); the SDK checks its use of it, not its internals.
|
|
82
|
+
[[tool.mypy.overrides]]
|
|
83
|
+
module = ["livepeer_frameworks._generated.proto.*"]
|
|
84
|
+
ignore_errors = true
|
|
85
|
+
|
|
86
|
+
[[tool.mypy.overrides]]
|
|
87
|
+
module = ["standardwebhooks.*"]
|
|
88
|
+
ignore_missing_imports = true
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
"""Typed client for the FrameWorks GraphQL API."""
|
|
2
|
+
|
|
3
|
+
from ._forward import OpenEnum, UnknownMember
|
|
4
|
+
from ._generated.manifest import MIN_SERVER_VERSION, OPERATIONS, SDK_LINE, SDK_VERSION
|
|
5
|
+
from ._server_info import ServerStatus
|
|
6
|
+
from .client import AsyncFrameWorksClient, FrameWorksClient
|
|
7
|
+
from .errors import (
|
|
8
|
+
AuthenticationError,
|
|
9
|
+
FrameWorksError,
|
|
10
|
+
GraphQLError,
|
|
11
|
+
HTTPError,
|
|
12
|
+
NetworkError,
|
|
13
|
+
PaymentRequiredError,
|
|
14
|
+
ProtocolError,
|
|
15
|
+
RateLimitError,
|
|
16
|
+
ResultError,
|
|
17
|
+
SchemaMismatchError,
|
|
18
|
+
ServerError,
|
|
19
|
+
ServerTooOldError,
|
|
20
|
+
UnsupportedOperationError,
|
|
21
|
+
UploadError,
|
|
22
|
+
WebhookVerificationError,
|
|
23
|
+
)
|
|
24
|
+
from .pagination import (
|
|
25
|
+
apaginate_offset,
|
|
26
|
+
apaginate_page_token,
|
|
27
|
+
apaginate_relay,
|
|
28
|
+
paginate_offset,
|
|
29
|
+
paginate_page_token,
|
|
30
|
+
paginate_relay,
|
|
31
|
+
)
|
|
32
|
+
from .playback_token import sign_playback_token
|
|
33
|
+
from .results import expect_result
|
|
34
|
+
from .retry import DEFAULT_RETRY_POLICY, RetryPolicy
|
|
35
|
+
from .upload import async_upload_vod, upload_vod
|
|
36
|
+
from .webhooks import WebhookEvent, WebhookReceiver, parse_webhook_event
|
|
37
|
+
|
|
38
|
+
__version__ = SDK_VERSION
|
|
39
|
+
|
|
40
|
+
__all__ = [
|
|
41
|
+
"AsyncFrameWorksClient",
|
|
42
|
+
"AuthenticationError",
|
|
43
|
+
"DEFAULT_RETRY_POLICY",
|
|
44
|
+
"FrameWorksClient",
|
|
45
|
+
"FrameWorksError",
|
|
46
|
+
"GraphQLError",
|
|
47
|
+
"HTTPError",
|
|
48
|
+
"MIN_SERVER_VERSION",
|
|
49
|
+
"NetworkError",
|
|
50
|
+
"OPERATIONS",
|
|
51
|
+
"OpenEnum",
|
|
52
|
+
"PaymentRequiredError",
|
|
53
|
+
"ProtocolError",
|
|
54
|
+
"RateLimitError",
|
|
55
|
+
"ResultError",
|
|
56
|
+
"RetryPolicy",
|
|
57
|
+
"SDK_LINE",
|
|
58
|
+
"SDK_VERSION",
|
|
59
|
+
"SchemaMismatchError",
|
|
60
|
+
"ServerError",
|
|
61
|
+
"ServerStatus",
|
|
62
|
+
"ServerTooOldError",
|
|
63
|
+
"UnknownMember",
|
|
64
|
+
"UnsupportedOperationError",
|
|
65
|
+
"UploadError",
|
|
66
|
+
"WebhookEvent",
|
|
67
|
+
"WebhookReceiver",
|
|
68
|
+
"WebhookVerificationError",
|
|
69
|
+
"__version__",
|
|
70
|
+
"apaginate_offset",
|
|
71
|
+
"apaginate_page_token",
|
|
72
|
+
"apaginate_relay",
|
|
73
|
+
"async_upload_vod",
|
|
74
|
+
"expect_result",
|
|
75
|
+
"paginate_offset",
|
|
76
|
+
"paginate_page_token",
|
|
77
|
+
"paginate_relay",
|
|
78
|
+
"parse_webhook_event",
|
|
79
|
+
"sign_playback_token",
|
|
80
|
+
"upload_vod",
|
|
81
|
+
]
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
"""Decoding of result union members and enum values a newer server adds.
|
|
2
|
+
|
|
3
|
+
The SDK supports a range of server releases, and a later release may add a
|
|
4
|
+
member to a union or a value to an enum. The generated models use the types
|
|
5
|
+
below (codegen/forward_compat.py rewrites them), so such a response decodes
|
|
6
|
+
instead of failing validation."""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
from enum import Enum
|
|
11
|
+
from typing import Any, get_args
|
|
12
|
+
|
|
13
|
+
from pydantic import BaseModel, ConfigDict, GetCoreSchemaHandler, model_serializer
|
|
14
|
+
from pydantic_core import core_schema
|
|
15
|
+
|
|
16
|
+
# The tag the discriminator returns for a __typename no member declares. It
|
|
17
|
+
# cannot collide with a GraphQL type name.
|
|
18
|
+
_UNKNOWN_TAG = "<unknown>"
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class UnknownMember(BaseModel):
|
|
22
|
+
"""A union member this SDK does not know: a type a newer server added.
|
|
23
|
+
|
|
24
|
+
typename__ is its __typename and raw its JSON exactly as the server sent
|
|
25
|
+
it; dumping the member returns raw. expect_result raises it as a
|
|
26
|
+
ResultError carrying its __typename, message, and code."""
|
|
27
|
+
|
|
28
|
+
model_config = ConfigDict(frozen=True)
|
|
29
|
+
|
|
30
|
+
typename__: str
|
|
31
|
+
raw: dict[str, Any]
|
|
32
|
+
|
|
33
|
+
@model_serializer
|
|
34
|
+
def _dump_raw(self) -> dict[str, Any]:
|
|
35
|
+
return self.raw
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
class OpenUnion:
|
|
39
|
+
"""Annotated metadata for a generated union field: members are chosen by
|
|
40
|
+
__typename, and a __typename no member declares becomes an UnknownMember.
|
|
41
|
+
|
|
42
|
+
The annotated type is Union[<generated members>, UnknownMember]; each
|
|
43
|
+
generated member declares its __typename as typename__: Literal[...]."""
|
|
44
|
+
|
|
45
|
+
def __get_pydantic_core_schema__(self, source: Any, handler: GetCoreSchemaHandler) -> core_schema.CoreSchema:
|
|
46
|
+
choices: dict[str, core_schema.CoreSchema] = {}
|
|
47
|
+
for member in get_args(source):
|
|
48
|
+
if member is UnknownMember:
|
|
49
|
+
continue
|
|
50
|
+
field = member.model_fields.get("typename__") if isinstance(member, type) and issubclass(member, BaseModel) else None
|
|
51
|
+
tags = get_args(field.annotation) if field is not None else ()
|
|
52
|
+
if not tags:
|
|
53
|
+
raise TypeError(f"union member {member!r} does not declare typename__ as a Literal")
|
|
54
|
+
for typename in tags:
|
|
55
|
+
choices[typename] = handler.generate_schema(member)
|
|
56
|
+
choices[_UNKNOWN_TAG] = core_schema.no_info_before_validator_function(
|
|
57
|
+
_unknown_member_input, handler.generate_schema(UnknownMember)
|
|
58
|
+
)
|
|
59
|
+
known = frozenset(choices) - {_UNKNOWN_TAG}
|
|
60
|
+
|
|
61
|
+
def tag(value: Any) -> str | None:
|
|
62
|
+
if isinstance(value, UnknownMember):
|
|
63
|
+
return _UNKNOWN_TAG
|
|
64
|
+
typename = value.get("__typename") if isinstance(value, dict) else getattr(value, "typename__", None)
|
|
65
|
+
if not isinstance(typename, str):
|
|
66
|
+
return None
|
|
67
|
+
return typename if typename in known else _UNKNOWN_TAG
|
|
68
|
+
|
|
69
|
+
return core_schema.tagged_union_schema(choices, tag)
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
def _unknown_member_input(value: Any) -> Any:
|
|
73
|
+
if isinstance(value, dict):
|
|
74
|
+
return {"typename__": value["__typename"], "raw": dict(value)}
|
|
75
|
+
return value
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
class OpenEnum(str, Enum):
|
|
79
|
+
"""Base of the generated enums. A value this SDK does not know, which a
|
|
80
|
+
newer server added, decodes to a member of the enum whose value and name
|
|
81
|
+
are the server's string and whose is_unknown is True; it is not one of
|
|
82
|
+
the enum's declared members, so an exhaustive match falls through to its
|
|
83
|
+
default case."""
|
|
84
|
+
|
|
85
|
+
@classmethod
|
|
86
|
+
def _missing_(cls, value: object) -> Any:
|
|
87
|
+
if not isinstance(value, str):
|
|
88
|
+
return None
|
|
89
|
+
member = str.__new__(cls, value)
|
|
90
|
+
member._name_ = value
|
|
91
|
+
member._value_ = value
|
|
92
|
+
return member
|
|
93
|
+
|
|
94
|
+
@property
|
|
95
|
+
def is_unknown(self) -> bool:
|
|
96
|
+
"""Whether the value is one this SDK does not know."""
|
|
97
|
+
return self._value_ not in type(self)._value2member_map_
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# Code generated by scripts/sdkcontract from pkg/graphql/public and the event registry. DO NOT EDIT.
|
|
2
|
+
|
|
3
|
+
from typing import Final
|
|
4
|
+
|
|
5
|
+
import betterproto2
|
|
6
|
+
|
|
7
|
+
from .proto.frameworks.events.public.v1 import (
|
|
8
|
+
AccountSuspended,
|
|
9
|
+
ApiTokenCreated,
|
|
10
|
+
ApiTokenRevoked,
|
|
11
|
+
BillingDetailsUpdated,
|
|
12
|
+
ClipFailed,
|
|
13
|
+
ClipReady,
|
|
14
|
+
ClipRequested,
|
|
15
|
+
CustomDomainFailed,
|
|
16
|
+
CustomDomainVerified,
|
|
17
|
+
InvoiceCreated,
|
|
18
|
+
InvoicePaid,
|
|
19
|
+
MultistreamStatusChanged,
|
|
20
|
+
PaymentFailed,
|
|
21
|
+
RecordingFailed,
|
|
22
|
+
RecordingReady,
|
|
23
|
+
StreamConnected,
|
|
24
|
+
StreamCreated,
|
|
25
|
+
StreamDeleted,
|
|
26
|
+
StreamIdle,
|
|
27
|
+
StreamKeyRotated,
|
|
28
|
+
StreamLive,
|
|
29
|
+
StreamUpdated,
|
|
30
|
+
TopupCredited,
|
|
31
|
+
UploadAborted,
|
|
32
|
+
UploadCompleted,
|
|
33
|
+
UploadCreated,
|
|
34
|
+
UploadFailed,
|
|
35
|
+
UploadReady,
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
PUBLIC_EVENT_MESSAGES: Final[dict[str, type[betterproto2.Message]]] = {
|
|
39
|
+
"account.suspended": AccountSuspended,
|
|
40
|
+
"api_token.created": ApiTokenCreated,
|
|
41
|
+
"api_token.revoked": ApiTokenRevoked,
|
|
42
|
+
"billing.details_updated": BillingDetailsUpdated,
|
|
43
|
+
"billing.invoice_created": InvoiceCreated,
|
|
44
|
+
"billing.invoice_paid": InvoicePaid,
|
|
45
|
+
"billing.payment_failed": PaymentFailed,
|
|
46
|
+
"billing.topup_credited": TopupCredited,
|
|
47
|
+
"clip.failed": ClipFailed,
|
|
48
|
+
"clip.ready": ClipReady,
|
|
49
|
+
"clip.requested": ClipRequested,
|
|
50
|
+
"custom_domain.failed": CustomDomainFailed,
|
|
51
|
+
"custom_domain.verified": CustomDomainVerified,
|
|
52
|
+
"multistream.status_changed": MultistreamStatusChanged,
|
|
53
|
+
"recording.failed": RecordingFailed,
|
|
54
|
+
"recording.ready": RecordingReady,
|
|
55
|
+
"stream.connected": StreamConnected,
|
|
56
|
+
"stream.created": StreamCreated,
|
|
57
|
+
"stream.deleted": StreamDeleted,
|
|
58
|
+
"stream.idle": StreamIdle,
|
|
59
|
+
"stream.key_rotated": StreamKeyRotated,
|
|
60
|
+
"stream.live": StreamLive,
|
|
61
|
+
"stream.updated": StreamUpdated,
|
|
62
|
+
"upload.aborted": UploadAborted,
|
|
63
|
+
"upload.completed": UploadCompleted,
|
|
64
|
+
"upload.created": UploadCreated,
|
|
65
|
+
"upload.failed": UploadFailed,
|
|
66
|
+
"upload.ready": UploadReady,
|
|
67
|
+
}
|