xenfra-sdk 0.1.6__py3-none-any.whl → 0.1.8__py3-none-any.whl

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.
@@ -133,6 +133,7 @@ class DeploymentsManager(BaseManager):
133
133
  try:
134
134
  # Use httpx to stream the SSE response
135
135
  import httpx
136
+ import os
136
137
 
137
138
  headers = {
138
139
  "Authorization": f"Bearer {self._client._token}",
@@ -140,7 +141,19 @@ class DeploymentsManager(BaseManager):
140
141
  "Content-Type": "application/json",
141
142
  }
142
143
 
143
- url = f"{self._client.api_url}/deployments/stream"
144
+ # Use streaming API URL if available (bypasses Cloudflare timeout)
145
+ # Otherwise fall back to regular API URL
146
+ streaming_api_url = os.getenv("XENFRA_STREAMING_API_URL")
147
+ if streaming_api_url:
148
+ base_url = streaming_api_url
149
+ elif self._client.api_url == "https://api.xenfra.tech":
150
+ # Production: use non-proxied streaming subdomain
151
+ base_url = "https://stream.xenfra.tech"
152
+ else:
153
+ # Local/dev: use regular API URL
154
+ base_url = self._client.api_url
155
+
156
+ url = f"{base_url}/deployments/stream"
144
157
 
145
158
  with httpx.stream(
146
159
  "POST",
@@ -151,14 +164,18 @@ class DeploymentsManager(BaseManager):
151
164
  ) as response:
152
165
  # Check status before consuming stream
153
166
  if response.status_code not in [200, 201, 202]:
154
- # For streaming responses, we can't access .text directly
155
- # Read the error from the stream
156
- error_lines = []
157
- for line in response.iter_lines():
158
- error_lines.append(line)
159
- if len(error_lines) > 10: # Limit error message size
160
- break
161
- error_text = "\n".join(error_lines) if error_lines else "Unknown error"
167
+ # For error responses from streaming endpoint, read via iteration
168
+ error_text = ""
169
+ try:
170
+ for chunk in response.iter_bytes():
171
+ error_text += chunk.decode('utf-8', errors='ignore')
172
+ if len(error_text) > 1000: # Limit error message size
173
+ break
174
+ if not error_text:
175
+ error_text = "Unknown error"
176
+ except Exception as e:
177
+ error_text = f"Could not read error response: {e}"
178
+
162
179
  raise XenfraAPIError(
163
180
  status_code=response.status_code,
164
181
  detail=f"Deployment failed: {error_text}"
@@ -175,13 +192,23 @@ class DeploymentsManager(BaseManager):
175
192
  current_event = line[6:].strip()
176
193
  elif line.startswith("data:"):
177
194
  data = line[5:].strip()
195
+
196
+ # Get event type
197
+ event_type = current_event if 'current_event' in locals() else "message"
198
+
199
+ # Skip keep-alive events (used to prevent proxy timeouts)
200
+ if event_type == "keep-alive":
201
+ if 'current_event' in locals():
202
+ del current_event
203
+ continue
204
+
178
205
  try:
179
206
  # Try to parse as JSON
180
207
  data_parsed = json.loads(data)
181
- yield {"event": current_event if 'current_event' in locals() else "message", "data": data_parsed}
208
+ yield {"event": event_type, "data": data_parsed}
182
209
  except json.JSONDecodeError:
183
210
  # If not JSON, yield as plain text
184
- yield {"event": current_event if 'current_event' in locals() else "message", "data": data}
211
+ yield {"event": event_type, "data": data}
185
212
 
186
213
  # Reset current_event
187
214
  if 'current_event' in locals():
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: xenfra-sdk
3
- Version: 0.1.6
3
+ Version: 0.1.8
4
4
  Summary: Xenfra SDK: Core engine and utilities for the Xenfra platform.
5
5
  Author: xenfra-cloud
6
6
  Author-email: xenfra-cloud <xenfracloud@gmail.com>
@@ -18,7 +18,7 @@ xenfra_sdk/privacy.py,sha256=ksGf5L9PVtRP-xZS3T-Gj7MKfexTqIMgbFLoYkIESOE,5662
18
18
  xenfra_sdk/recipes.py,sha256=g_UKQIcdSokYh7zn186mzDTr08P034-KZ1iiDNELyP4,877
19
19
  xenfra_sdk/resources/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
20
20
  xenfra_sdk/resources/base.py,sha256=C6BuZfhR-oU5ecHSfkGG6ZLU6MHGXUyCWoy1F-yTIf8,84
21
- xenfra_sdk/resources/deployments.py,sha256=sgxSFBwI4bf5-vS28ruCwrNN72c5UFoMFefdXRjgE30,7765
21
+ xenfra_sdk/resources/deployments.py,sha256=OEtvBevRj6alN1uyEIyZSxBstIhUhngbVpCZ3ryd_o0,8868
22
22
  xenfra_sdk/resources/intelligence.py,sha256=Y11K6_iXfm2QKTbH1vUmt45MifLoVtZtlHEkqbzmTzs,3418
23
23
  xenfra_sdk/resources/projects.py,sha256=EsCVXmqkhWl_Guz_8WDQDi3kAm1Wyg1rjXcyAigPD6E,3712
24
24
  xenfra_sdk/security.py,sha256=Px887RRb1BUDXaPUrxmQITJ1mHyOyupCJqEDZ78F7Tk,1240
@@ -26,6 +26,6 @@ xenfra_sdk/templates/Dockerfile.j2,sha256=GXc0JiaF-HsxTQS15Gs2fcvsIhA1EHnwapdFVi
26
26
  xenfra_sdk/templates/cloud-init.sh.j2,sha256=NKIwtL9OgnlK2NnYRZI3gWC9aYl6wNPsS6r14g8eHQQ,2290
27
27
  xenfra_sdk/templates/docker-compose.yml.j2,sha256=qMHiatuZlxiYZ1pE_g2ag1M798MvQbeq0cVTVK07jkM,893
28
28
  xenfra_sdk/utils.py,sha256=d8eCjjV32QwqoJa759CEcETnnsjG5qVKDLQ84yYtlus,3898
29
- xenfra_sdk-0.1.6.dist-info/WHEEL,sha256=KSLUh82mDPEPk0Bx0ScXlWL64bc8KmzIPNcpQZFV-6E,79
30
- xenfra_sdk-0.1.6.dist-info/METADATA,sha256=3Ey9dYNU-gA6scZTDLldudhPrgR2kkB5ggh_g86-yQU,3980
31
- xenfra_sdk-0.1.6.dist-info/RECORD,,
29
+ xenfra_sdk-0.1.8.dist-info/WHEEL,sha256=KSLUh82mDPEPk0Bx0ScXlWL64bc8KmzIPNcpQZFV-6E,79
30
+ xenfra_sdk-0.1.8.dist-info/METADATA,sha256=Mt6YJ3ZJnGi2LenFkzTqqKVf0exC4AiSg4h5UDm7Rk4,3980
31
+ xenfra_sdk-0.1.8.dist-info/RECORD,,