upstream-sdk-python 0.0.3__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.
@@ -0,0 +1,2 @@
1
+ venv
2
+ upstream_sdk/__pycache__/
@@ -0,0 +1,51 @@
1
+ Metadata-Version: 2.4
2
+ Name: upstream-sdk-python
3
+ Version: 0.0.3
4
+ Summary: Simple and open logging for your projects
5
+ Project-URL: Homepage, https://up.linus.my
6
+ Project-URL: Documentation, https://docs.linus.my/upstream
7
+ Project-URL: Repository, https://github.com/linusdotmy/upstream
8
+ License: CC BY-NC 4.0
9
+ Keywords: events,logging,logs,sdk,upstream
10
+ Classifier: Development Status :: 4 - Beta
11
+ Classifier: Intended Audience :: Developers
12
+ Classifier: License :: OSI Approved :: MIT License
13
+ Classifier: Programming Language :: Python :: 3
14
+ Classifier: Programming Language :: Python :: 3.8
15
+ Classifier: Programming Language :: Python :: 3.9
16
+ Classifier: Programming Language :: Python :: 3.10
17
+ Classifier: Programming Language :: Python :: 3.11
18
+ Classifier: Programming Language :: Python :: 3.12
19
+ Classifier: Programming Language :: Python :: 3.13
20
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
21
+ Requires-Python: >=3.8
22
+ Description-Content-Type: text/markdown
23
+
24
+ # upstream-sdk
25
+
26
+ Simple and open logging for your projects.
27
+
28
+ ## Installation
29
+
30
+ ```bash
31
+ pip install upstream-sdk
32
+ ```
33
+
34
+ ## Quick Start
35
+
36
+ ```python
37
+ from upstream_sdk import Upstream, EventProps
38
+
39
+ up = Upstream("YOUR_API_KEY")
40
+
41
+ up.events.ingest(EventProps(
42
+ title="Project Deployed",
43
+ icon="😁",
44
+ ))
45
+ ```
46
+
47
+ That's just scratching the surface. You can log complex events with JSON, timeline events, descriptions, fields, and even add action buttons.
48
+
49
+ ## License
50
+
51
+ MIT
@@ -0,0 +1,28 @@
1
+ # upstream-sdk
2
+
3
+ Simple and open logging for your projects.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ pip install upstream-sdk
9
+ ```
10
+
11
+ ## Quick Start
12
+
13
+ ```python
14
+ from upstream_sdk import Upstream, EventProps
15
+
16
+ up = Upstream("YOUR_API_KEY")
17
+
18
+ up.events.ingest(EventProps(
19
+ title="Project Deployed",
20
+ icon="😁",
21
+ ))
22
+ ```
23
+
24
+ That's just scratching the surface. You can log complex events with JSON, timeline events, descriptions, fields, and even add action buttons.
25
+
26
+ ## License
27
+
28
+ MIT
@@ -0,0 +1,34 @@
1
+ [build-system]
2
+ requires = ["hatchling"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [project]
6
+ name = "upstream-sdk-python"
7
+ version = "0.0.3"
8
+ description = "Simple and open logging for your projects"
9
+ readme = "README.md"
10
+ license = {text = "CC BY-NC 4.0"}
11
+ requires-python = ">=3.8"
12
+ keywords = ["upstream", "logging", "sdk", "events", "logs"]
13
+ classifiers = [
14
+ "Development Status :: 4 - Beta",
15
+ "Intended Audience :: Developers",
16
+ "License :: OSI Approved :: MIT License",
17
+ "Programming Language :: Python :: 3",
18
+ "Programming Language :: Python :: 3.8",
19
+ "Programming Language :: Python :: 3.9",
20
+ "Programming Language :: Python :: 3.10",
21
+ "Programming Language :: Python :: 3.11",
22
+ "Programming Language :: Python :: 3.12",
23
+ "Programming Language :: Python :: 3.13",
24
+ "Topic :: Software Development :: Libraries :: Python Modules",
25
+ ]
26
+
27
+ [project.urls]
28
+ Homepage = "https://up.linus.my"
29
+ Documentation = "https://docs.linus.my/upstream"
30
+ Repository = "https://github.com/linusdotmy/upstream"
31
+
32
+ [tool.hatch.build.targets.wheel]
33
+ packages = ["upstream_sdk"]
34
+
@@ -0,0 +1,4 @@
1
+ from .client import Upstream
2
+ from .types import Action, EventProps, Field, TimelineEvent
3
+
4
+ __all__ = ["Action", "EventProps", "Field", "TimelineEvent", "Upstream"]
@@ -0,0 +1,47 @@
1
+ import json
2
+ import urllib.request
3
+ from dataclasses import asdict
4
+ from typing import Optional
5
+
6
+ from .types import EventProps
7
+
8
+
9
+ class _EventsAPI:
10
+ def __init__(self, api_key: str, host: str):
11
+ self._api_key = api_key
12
+ self._host = host.rstrip("/")
13
+
14
+ def ingest(self, payload: EventProps) -> dict:
15
+ url = f"{self._host}/api/events/ingest"
16
+ data = asdict(payload)
17
+
18
+ # Convert snake_case to camelCase for API compatibility
19
+ if "created_at" in data:
20
+ data["createdAt"] = data.pop("created_at")
21
+
22
+ # Remove None values to keep payload clean
23
+ data = {k: v for k, v in data.items() if v is not None}
24
+
25
+ req = urllib.request.Request(
26
+ url,
27
+ data=json.dumps(data, default=str).encode("utf-8"),
28
+ headers={
29
+ "Content-Type": "application/json",
30
+ "x-api-key": self._api_key,
31
+ },
32
+ method="POST",
33
+ )
34
+
35
+ try:
36
+ with urllib.request.urlopen(req) as response:
37
+ return json.loads(response.read().decode("utf-8"))
38
+ except urllib.error.HTTPError as e:
39
+ body = e.read().decode("utf-8")
40
+ raise Exception(f"Upstream API error ({e.code}): {body}") from e
41
+
42
+
43
+ class Upstream:
44
+ def __init__(self, api_key: str, host: Optional[str] = None):
45
+ self._api_key = api_key
46
+ self._host = host or "https://up.linus.my"
47
+ self.events = _EventsAPI(self._api_key, self._host)
@@ -0,0 +1,35 @@
1
+ from dataclasses import dataclass
2
+ from typing import Any, List, Literal, Optional
3
+
4
+
5
+ @dataclass
6
+ class Field:
7
+ name: str
8
+ value: str
9
+
10
+
11
+ @dataclass
12
+ class TimelineEvent:
13
+ icon: str
14
+ time: str
15
+ content: str
16
+
17
+
18
+ @dataclass
19
+ class Action:
20
+ title: str
21
+ type: Literal["default", "secondary", "ghost"]
22
+ url: str
23
+
24
+
25
+ @dataclass
26
+ class EventProps:
27
+ title: str
28
+ icon: str
29
+ created_at: Optional[str] = None
30
+ content: Optional[str] = None
31
+ category: Optional[str] = None
32
+ fields: Optional[List[Field]] = None
33
+ events: Optional[List[TimelineEvent]] = None
34
+ data: Optional[Any] = None
35
+ actions: Optional[List[Action]] = None