streamgine 1.0.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.
- streamgine-1.0.0/.gitignore +47 -0
- streamgine-1.0.0/PKG-INFO +323 -0
- streamgine-1.0.0/PUBLISHING.md +69 -0
- streamgine-1.0.0/README.md +295 -0
- streamgine-1.0.0/examples/__init__.py +0 -0
- streamgine-1.0.0/examples/agent.py +61 -0
- streamgine-1.0.0/examples/agent_journey.py +219 -0
- streamgine-1.0.0/examples/serverless/README.md +81 -0
- streamgine-1.0.0/examples/serverless/__init__.py +0 -0
- streamgine-1.0.0/examples/serverless/handler.py +68 -0
- streamgine-1.0.0/examples/serverless/register.py +39 -0
- streamgine-1.0.0/examples/serverless/requirements.txt +1 -0
- streamgine-1.0.0/pyproject.toml +52 -0
- streamgine-1.0.0/src/streamgine/__init__.py +5 -0
- streamgine-1.0.0/src/streamgine/diff/__init__.py +40 -0
- streamgine-1.0.0/src/streamgine/diff/client.py +188 -0
- streamgine-1.0.0/src/streamgine/diff/constants.py +5 -0
- streamgine-1.0.0/src/streamgine/diff/credentials.py +153 -0
- streamgine-1.0.0/src/streamgine/diff/exceptions.py +9 -0
- streamgine-1.0.0/src/streamgine/diff/models.py +31 -0
- streamgine-1.0.0/src/streamgine/diff/webhooks.py +83 -0
- streamgine-1.0.0/tests/test_client.py +249 -0
- streamgine-1.0.0/tests/test_credentials.py +92 -0
- streamgine-1.0.0/tests/test_serverless_handler.py +70 -0
- streamgine-1.0.0/tests/test_webhooks.py +58 -0
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
node_modules/
|
|
2
|
+
apps/web/node_modules/
|
|
3
|
+
apps/web/dist/
|
|
4
|
+
|
|
5
|
+
# Vite build output (apps/web → public/)
|
|
6
|
+
public/assets/
|
|
7
|
+
public/index.html
|
|
8
|
+
public/favicon.svg
|
|
9
|
+
public/icons.svg
|
|
10
|
+
|
|
11
|
+
!.env.development.example
|
|
12
|
+
.DS_Store
|
|
13
|
+
|
|
14
|
+
# Local VS Code / Cursor multi-root workspace
|
|
15
|
+
diff-events.code-workspace
|
|
16
|
+
|
|
17
|
+
# Cursor agent skills (local Stripe tooling; reinstall per machine)
|
|
18
|
+
skills/
|
|
19
|
+
skills-lock.json
|
|
20
|
+
# Shared Cursor workflow skills are versioned, unlike the per-machine ones above
|
|
21
|
+
!.cursor-personal-configs/skills/
|
|
22
|
+
|
|
23
|
+
# Python client
|
|
24
|
+
clients/python/.pytest_cache/
|
|
25
|
+
.pytest_cache/
|
|
26
|
+
clients/python/.venv/
|
|
27
|
+
clients/python/dist/
|
|
28
|
+
clients/python/build/
|
|
29
|
+
clients/python/**/*.egg-info/
|
|
30
|
+
clients/python/**/__pycache__/
|
|
31
|
+
tools/python/**/__pycache__/
|
|
32
|
+
|
|
33
|
+
# Miss-rate / load datasets (generated locally)
|
|
34
|
+
tmp/
|
|
35
|
+
|
|
36
|
+
# Accidental root venv (use clients/python/.venv)
|
|
37
|
+
.venv/
|
|
38
|
+
|
|
39
|
+
# Stripe Projects (local; CLI-managed)
|
|
40
|
+
.projects/
|
|
41
|
+
.claude/
|
|
42
|
+
CLAUDE.md
|
|
43
|
+
.cursorignore
|
|
44
|
+
.env
|
|
45
|
+
.env.*
|
|
46
|
+
!.env.development.example
|
|
47
|
+
!.env.example
|
|
@@ -0,0 +1,323 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: streamgine
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Streamgine Python SDK — Diff by Streamgine webhooks client and future modules.
|
|
5
|
+
Project-URL: Homepage, https://streamgine.com
|
|
6
|
+
Project-URL: Documentation, https://diff.streamgine.com/docs.md
|
|
7
|
+
Project-URL: Repository, https://github.com/scurtutech/diff-events-service
|
|
8
|
+
Project-URL: Issues, https://github.com/scurtutech/diff-events-service/issues
|
|
9
|
+
Project-URL: Changelog, https://github.com/scurtutech/diff-events-service/releases
|
|
10
|
+
Author-email: Streamgine <hello@streamgine.com>
|
|
11
|
+
License: MIT
|
|
12
|
+
Keywords: agents,compliance,corporate-standing,diff,streamgine,webhooks
|
|
13
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
14
|
+
Classifier: Intended Audience :: Developers
|
|
15
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
21
|
+
Classifier: Topic :: Internet :: WWW/HTTP
|
|
22
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
23
|
+
Requires-Python: >=3.10
|
|
24
|
+
Requires-Dist: httpx>=0.27.0
|
|
25
|
+
Provides-Extra: dev
|
|
26
|
+
Requires-Dist: pytest>=8.0; extra == 'dev'
|
|
27
|
+
Description-Content-Type: text/markdown
|
|
28
|
+
|
|
29
|
+
# streamgine — Python SDK
|
|
30
|
+
|
|
31
|
+
**Diff by Streamgine** lives under the `diff` module. Install once; add more Streamgine modules (training data, etc.) under the same package later.
|
|
32
|
+
|
|
33
|
+
This directory is the **customer package** published to PyPI. Repo-only load tests and dev agents live in [`tools/python/`](../../tools/python/README.md) — not shipped to customers.
|
|
34
|
+
|
|
35
|
+
**Today:** one wheel `streamgine` = Diff (`from streamgine import diff`). **Next products** (e.g. training-data) get their own wheels (`streamgine-diff`, `streamgine-training`, …) under the same `streamgine` import namespace — see [PUBLISHING.md](PUBLISHING.md) and `.cursor/rules/python-client.mdc`. Do not grow a fat single package.
|
|
36
|
+
|
|
37
|
+
**Product:** [diff.streamgine.com](https://diff.streamgine.com) · **Docs:** [docs.md](https://diff.streamgine.com/docs.md) · **California:** [coverage](https://diff.streamgine.com/california) · **Use cases:** [risk monitoring](https://diff.streamgine.com/use-cases/risk-monitoring), [AI agents](https://diff.streamgine.com/use-cases/ai-agents) · **Repo:** [github.com/scurtutech/diff-events-service](https://github.com/scurtutech/diff-events-service)
|
|
38
|
+
|
|
39
|
+
```python
|
|
40
|
+
from streamgine import diff
|
|
41
|
+
|
|
42
|
+
# Once at startup — pick ONE download from /account:
|
|
43
|
+
diff.configure("diff-streamgine-credentials.json")
|
|
44
|
+
# OR: source diff-streamgine-env.sh then diff.configure()
|
|
45
|
+
client = diff.DiffClient()
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
Install from PyPI:
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
python3 -m pip install streamgine
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
Or from this repo:
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
cd clients/python
|
|
58
|
+
python3 -m venv .venv && source .venv/bin/activate
|
|
59
|
+
python -m pip install .
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
Requires Python 3.10+. One dependency: [httpx](https://www.python-httpx.org/) (TLS verification enabled by default).
|
|
63
|
+
|
|
64
|
+
## Credentials (one setup point)
|
|
65
|
+
|
|
66
|
+
Call `diff.configure()` **once** at process startup. Every `DiffClient()` and `verify_webhook()` reads from that config.
|
|
67
|
+
|
|
68
|
+
Download from `/account` or checkout — filenames are fixed:
|
|
69
|
+
|
|
70
|
+
| Download | Then |
|
|
71
|
+
| ---------------------------------- | ------------------------------------------------------- |
|
|
72
|
+
| `diff-streamgine-credentials.json` | `diff.configure("diff-streamgine-credentials.json")` |
|
|
73
|
+
| `diff-streamgine-env.sh` | `source diff-streamgine-env.sh` then `diff.configure()` |
|
|
74
|
+
|
|
75
|
+
**Option A — credentials JSON:**
|
|
76
|
+
|
|
77
|
+
```python
|
|
78
|
+
diff.configure("diff-streamgine-credentials.json")
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
**Option B — env script:**
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
source diff-streamgine-env.sh
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
```python
|
|
88
|
+
diff.configure()
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
Do **not** pass API keys or signing secrets to `DiffClient()` or `verify_webhook()` in normal use.
|
|
92
|
+
|
|
93
|
+
## Zero-setup agent (copy-paste)
|
|
94
|
+
|
|
95
|
+
```bash
|
|
96
|
+
python3 -m venv .venv
|
|
97
|
+
source .venv/bin/activate
|
|
98
|
+
python -m pip install -e . fastapi uvicorn
|
|
99
|
+
# Customer path: download from /account, then ONE of:
|
|
100
|
+
# source diff-streamgine-env.sh
|
|
101
|
+
# # or keep diff-streamgine-credentials.json next to the process
|
|
102
|
+
# Local repo seed (AUTH_ENABLED): npm run seed:dev-customer, then export printed keys
|
|
103
|
+
source diff-streamgine-env.sh # or configure("diff-streamgine-credentials.json") in code
|
|
104
|
+
python -m uvicorn examples.agent:app --port 8000
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
Runnable source: [`examples/agent.py`](examples/agent.py). Calls `register_test()` on startup; within ~1s you should see `after={'test': 'success'}` on topic `diff-event.test`.
|
|
108
|
+
|
|
109
|
+
**Serverless (AWS Lambda):** [`examples/serverless/`](examples/serverless/README.md) — deploy `handler.py`, run `register.py` once, receive test heartbeats in CloudWatch.
|
|
110
|
+
|
|
111
|
+
**Agent journey (production filters):** [`examples/agent_journey.py`](examples/agent_journey.py).
|
|
112
|
+
|
|
113
|
+
Docker worker reaching a host agent:
|
|
114
|
+
|
|
115
|
+
```bash
|
|
116
|
+
export DIFF_CALLBACK_URL=http://host.docker.internal:8000/webhooks/diff
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
## Test heartbeats (start here)
|
|
120
|
+
|
|
121
|
+
Before wiring real registry events, confirm your agent receives signed webhooks:
|
|
122
|
+
|
|
123
|
+
```python
|
|
124
|
+
from streamgine import diff
|
|
125
|
+
|
|
126
|
+
diff.configure() # after: source diff-streamgine-env.sh OR configure("diff-streamgine-credentials.json")
|
|
127
|
+
client = diff.DiffClient()
|
|
128
|
+
client.register_test(callback_url="https://your-agent.example/webhooks/diff")
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
Filter on **`event.is_test_heartbeat`** (or `after == {"test": "success"}`). The service sends this every second:
|
|
132
|
+
|
|
133
|
+
```json
|
|
134
|
+
{
|
|
135
|
+
"action": "INSERT",
|
|
136
|
+
"after": { "test": "success" }
|
|
137
|
+
}
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
No `entity_id` on test events.
|
|
141
|
+
|
|
142
|
+
## Quick start (production registry events)
|
|
143
|
+
|
|
144
|
+
```python
|
|
145
|
+
from streamgine import diff
|
|
146
|
+
|
|
147
|
+
diff.configure()
|
|
148
|
+
client = diff.DiffClient()
|
|
149
|
+
client.register(
|
|
150
|
+
match={
|
|
151
|
+
"state": "CA",
|
|
152
|
+
"principal_city": "San Francisco",
|
|
153
|
+
},
|
|
154
|
+
actions=["INSERT"],
|
|
155
|
+
callback_url="https://your-agent.example/webhooks/diff",
|
|
156
|
+
)
|
|
157
|
+
client.close()
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
`INSERT` = newly added company, `UPDATE` = changed, `DELETE` = removed. Omit `actions` to receive every matching state/city event.
|
|
161
|
+
|
|
162
|
+
### Search current companies (full story)
|
|
163
|
+
|
|
164
|
+
Webhooks deliver changes. Search returns **current** snapshots:
|
|
165
|
+
|
|
166
|
+
```python
|
|
167
|
+
from streamgine import diff
|
|
168
|
+
|
|
169
|
+
diff.configure()
|
|
170
|
+
client = diff.DiffClient()
|
|
171
|
+
result = client.search(
|
|
172
|
+
query={"match": {"principalCity": "San Francisco"}},
|
|
173
|
+
size=10,
|
|
174
|
+
)
|
|
175
|
+
for company in result["entities"]:
|
|
176
|
+
print(company.get("entity_name"), company.get("entity_number"))
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
Agent journey: **Search → Watch → Qualify → Act → Stay current** (see [`/docs.md`](../../public/docs.md)).
|
|
180
|
+
|
|
181
|
+
### 2. Verify inbound webhooks (required)
|
|
182
|
+
|
|
183
|
+
Always verify **raw request bytes** before trusting JSON. The worker signs the exact JSON body with HMAC-SHA256.
|
|
184
|
+
|
|
185
|
+
```python
|
|
186
|
+
from streamgine import diff
|
|
187
|
+
|
|
188
|
+
diff.configure()
|
|
189
|
+
|
|
190
|
+
def handle_webhook(raw_body: bytes, signature: str | None):
|
|
191
|
+
try:
|
|
192
|
+
event = diff.verify_webhook(raw_body, signature)
|
|
193
|
+
except diff.WebhookVerificationError:
|
|
194
|
+
return 401, {"error": "invalid signature"}
|
|
195
|
+
|
|
196
|
+
print(event.action, event.entity_id, event.after)
|
|
197
|
+
return 200, {"ok": True}
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
**FastAPI**
|
|
201
|
+
|
|
202
|
+
```python
|
|
203
|
+
from fastapi import FastAPI, Header, Request, Response
|
|
204
|
+
|
|
205
|
+
from streamgine import diff
|
|
206
|
+
|
|
207
|
+
app = FastAPI()
|
|
208
|
+
|
|
209
|
+
@app.on_event("startup")
|
|
210
|
+
def setup() -> None:
|
|
211
|
+
diff.configure()
|
|
212
|
+
|
|
213
|
+
@app.post("/webhooks/diff")
|
|
214
|
+
async def diff_webhook(
|
|
215
|
+
request: Request,
|
|
216
|
+
response: Response,
|
|
217
|
+
x_diff_signature: str | None = Header(default=None, alias="X-Diff-Signature"),
|
|
218
|
+
):
|
|
219
|
+
raw = await request.body()
|
|
220
|
+
try:
|
|
221
|
+
event = diff.verify_webhook(raw, x_diff_signature)
|
|
222
|
+
except diff.WebhookVerificationError:
|
|
223
|
+
response.status_code = 401
|
|
224
|
+
return {"error": "invalid signature"}
|
|
225
|
+
|
|
226
|
+
# Your agent logic here
|
|
227
|
+
return {"ok": True, "entity_id": event.entity_id}
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
**Flask**
|
|
231
|
+
|
|
232
|
+
```python
|
|
233
|
+
from flask import Flask, request
|
|
234
|
+
|
|
235
|
+
from streamgine import diff
|
|
236
|
+
|
|
237
|
+
app = Flask(__name__)
|
|
238
|
+
diff.configure()
|
|
239
|
+
|
|
240
|
+
@app.post("/webhooks/diff")
|
|
241
|
+
def webhook():
|
|
242
|
+
try:
|
|
243
|
+
event = diff.verify_webhook(
|
|
244
|
+
request.get_data(),
|
|
245
|
+
request.headers.get("X-Diff-Signature"),
|
|
246
|
+
)
|
|
247
|
+
except diff.WebhookVerificationError:
|
|
248
|
+
return {"error": "invalid signature"}, 401
|
|
249
|
+
|
|
250
|
+
return {"ok": True, "action": event.action}
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
## Security
|
|
254
|
+
|
|
255
|
+
| Practice | How this client helps |
|
|
256
|
+
| ---------------------------- | --------------------------------------------------------------------------------------------- |
|
|
257
|
+
| Verify every webhook | `diff.verify_webhook()` uses `hmac.compare_digest` (timing-safe) on the raw body |
|
|
258
|
+
| Match worker algorithm | Same as Node: `HMAC-SHA256(secret, raw_json_bytes)` → header `X-Diff-Signature: sha256=<hex>` |
|
|
259
|
+
| Parse JSON only after verify | Tampered bodies fail before `WebhookEvent` is built |
|
|
260
|
+
| HTTPS in production | `DiffClient(verify_tls=True)` (default); use `https://` callback URLs |
|
|
261
|
+
| Keep secrets out of code | One `configure()` from JSON or env — never scatter keys in constructors |
|
|
262
|
+
|
|
263
|
+
Never log the signing secret or skip signature verification in production.
|
|
264
|
+
|
|
265
|
+
### Credentials file (after checkout)
|
|
266
|
+
|
|
267
|
+
Download **`diff-streamgine-credentials.json`** (or **`diff-streamgine-env.sh`**) from `/account` / checkout. JSON format (version `1`):
|
|
268
|
+
|
|
269
|
+
```json
|
|
270
|
+
{
|
|
271
|
+
"version": 1,
|
|
272
|
+
"service": "diff.streamgine.com",
|
|
273
|
+
"customer_id": "cus_…",
|
|
274
|
+
"api_key": "de_live_…",
|
|
275
|
+
"signing_secret": "whsec_…",
|
|
276
|
+
"api_url": "https://diff.streamgine.com",
|
|
277
|
+
"env": {
|
|
278
|
+
"DIFF_API_KEY": "de_live_…",
|
|
279
|
+
"DIFF_SIGNING_SECRET": "whsec_…",
|
|
280
|
+
"DIFF_API_URL": "https://diff.streamgine.com"
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
```python
|
|
286
|
+
from streamgine import diff
|
|
287
|
+
|
|
288
|
+
diff.configure("diff-streamgine-credentials.json")
|
|
289
|
+
client = diff.DiffClient()
|
|
290
|
+
# diff.verify_webhook(...) uses the same signing secret automatically
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
## Auth
|
|
294
|
+
|
|
295
|
+
| Env (via `configure()`) | Used for |
|
|
296
|
+
| ----------------------- | --------------------------------------------------------------- |
|
|
297
|
+
| `DIFF_API_KEY` | `register()` / `register_test()` (customer Bearer) |
|
|
298
|
+
| `DIFF_PROVIDER_API_KEY` | `get_state()` and provider ingest when provider auth is enabled |
|
|
299
|
+
|
|
300
|
+
Register responses are slim (`ok` / subscription fields only — no Redis index maps).
|
|
301
|
+
|
|
302
|
+
## API surface (`streamgine.diff`)
|
|
303
|
+
|
|
304
|
+
| Symbol | Role |
|
|
305
|
+
| --------------------------- | ---------------------------------------------------------- |
|
|
306
|
+
| `configure()` | Load credentials once (JSON path or `DIFF_*` env) |
|
|
307
|
+
| `get_config()` | Read configured `ClientConfig` |
|
|
308
|
+
| `DiffClient` | `register()`, `register_test()`, `health()`, `get_state()` |
|
|
309
|
+
| `verify_webhook()` | Verify signature + return `WebhookEvent` |
|
|
310
|
+
| `DIFF_*` env name constants | `API_URL_ENV`, `API_KEY_ENV`, `SIGNING_SECRET_ENV`, … |
|
|
311
|
+
| `WebhookEvent` | Parsed `action`, optional `entity_id`, optional `after` |
|
|
312
|
+
| `WebhookVerificationError` | Invalid/missing signature or malformed payload |
|
|
313
|
+
| `SIGNATURE_HEADER` | `"X-Diff-Signature"` |
|
|
314
|
+
|
|
315
|
+
Direct imports also work: `from streamgine.diff import DiffClient`.
|
|
316
|
+
|
|
317
|
+
## Development
|
|
318
|
+
|
|
319
|
+
```bash
|
|
320
|
+
cd clients/python
|
|
321
|
+
python -m pip install -e ".[dev]"
|
|
322
|
+
pytest
|
|
323
|
+
```
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
# Publishing the Python client to PyPI
|
|
2
|
+
|
|
3
|
+
Package: **`streamgine`** · import: **`from streamgine import diff`**
|
|
4
|
+
|
|
5
|
+
Only `clients/python/src/streamgine/` is published. Repo dev harnesses (load test, standalone agents) live in [`tools/python/`](../../tools/python/README.md) and are **not** included in the wheel.
|
|
6
|
+
|
|
7
|
+
## Multi-product packaging (next products)
|
|
8
|
+
|
|
9
|
+
Today Diff is the only product, so one wheel named `streamgine` is fine.
|
|
10
|
+
|
|
11
|
+
When Streamgine adds another Python product (e.g. training-data):
|
|
12
|
+
|
|
13
|
+
1. Publish **one distribution per product**: `streamgine-diff`, `streamgine-training`, …
|
|
14
|
+
2. Keep imports under the **`streamgine`** namespace: `from streamgine import diff`, `from streamgine import training`
|
|
15
|
+
3. Optionally publish a thin meta package `streamgine` with extras (`streamgine[diff]`, `streamgine[training]`, `streamgine[all]`)
|
|
16
|
+
4. Target monorepo layout: `clients/python/packages/streamgine-diff/`, `…/streamgine-training/`, `…/streamgine-meta/`
|
|
17
|
+
|
|
18
|
+
Do **not** grow a single fat wheel that forces Diff customers to download unrelated products. Full rule: `.cursor/rules/python-client.mdc`.
|
|
19
|
+
|
|
20
|
+
## One-time setup
|
|
21
|
+
|
|
22
|
+
1. Create a [PyPI](https://pypi.org/) account and project (or use an existing one).
|
|
23
|
+
2. Create a **trusted publisher** on PyPI for this repo:
|
|
24
|
+
- Owner: `scurtutech`
|
|
25
|
+
- Repository: `diff-events-service`
|
|
26
|
+
- Workflow: `publish-python.yml`
|
|
27
|
+
- Environment: `pypi` (optional but recommended)
|
|
28
|
+
3. In GitHub → **Settings → Environments → pypi**, add protection rules if desired.
|
|
29
|
+
|
|
30
|
+
No long-lived API token is required when using [OIDC trusted publishing](https://docs.pypi.org/trusted-publishers/).
|
|
31
|
+
|
|
32
|
+
## Release
|
|
33
|
+
|
|
34
|
+
1. Bump `version` in `clients/python/pyproject.toml` and `clients/python/src/streamgine/__init__.py`.
|
|
35
|
+
2. Merge to `main`.
|
|
36
|
+
3. Create a GitHub **Release** (tag e.g. `python-v1.0.1`). Publishing runs automatically on `release: published`.
|
|
37
|
+
|
|
38
|
+
## Manual / dry run
|
|
39
|
+
|
|
40
|
+
**Actions → Publish Python client → Run workflow**
|
|
41
|
+
|
|
42
|
+
- Default **dry run** builds the wheel/sdist and runs tests only.
|
|
43
|
+
- Uncheck dry run to upload (requires trusted publisher configured).
|
|
44
|
+
|
|
45
|
+
## Local verify
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
cd clients/python
|
|
49
|
+
python -m pip install build
|
|
50
|
+
python -m build
|
|
51
|
+
pip install dist/streamgine-*.whl
|
|
52
|
+
pytest
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## Naming (do not rename on publish)
|
|
56
|
+
|
|
57
|
+
Wire identifiers stay as-is per product branding:
|
|
58
|
+
|
|
59
|
+
| Keep | Example |
|
|
60
|
+
| -------------------- | ---------------------------------------------------------------- |
|
|
61
|
+
| PyPI / pip name | `streamgine` (today = Diff only; later meta / `streamgine-diff`) |
|
|
62
|
+
| Import module | `streamgine.diff` (`from streamgine import diff`) |
|
|
63
|
+
| Client class | `DiffClient` |
|
|
64
|
+
| Env vars | `DIFF_*` via `configure()` |
|
|
65
|
+
| Signature header | `X-Diff-Signature` |
|
|
66
|
+
| Credentials filename | `diff-streamgine-credentials.json` |
|
|
67
|
+
| Env script filename | `diff-streamgine-env.sh` |
|
|
68
|
+
|
|
69
|
+
Customer-facing prose uses **Diff by Streamgine** or **Diff**, never **Diff Events**.
|