VibesAI-api 1.4.0__tar.gz → 1.4.2__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.
- {vibesai_api-1.4.0 → vibesai_api-1.4.2}/PKG-INFO +1 -1
- {vibesai_api-1.4.0 → vibesai_api-1.4.2}/VibesAI_api.egg-info/PKG-INFO +1 -1
- {vibesai_api-1.4.0 → vibesai_api-1.4.2}/pyproject.toml +1 -1
- {vibesai_api-1.4.0 → vibesai_api-1.4.2}/server/__init__.py +0 -0
- {vibesai_api-1.4.0 → vibesai_api-1.4.2}/server/app.py +0 -0
- {vibesai_api-1.4.0 → vibesai_api-1.4.2}/tests/test_all.py +2 -2
- {vibesai_api-1.4.0 → vibesai_api-1.4.2}/vibes_api/__init__.py +1 -1
- {vibesai_api-1.4.0 → vibesai_api-1.4.2}/vibes_api/client.py +61 -59
- {vibesai_api-1.4.0 → vibesai_api-1.4.2}/LICENSE +0 -0
- {vibesai_api-1.4.0 → vibesai_api-1.4.2}/README.md +0 -0
- {vibesai_api-1.4.0 → vibesai_api-1.4.2}/VibesAI_api.egg-info/SOURCES.txt +0 -0
- {vibesai_api-1.4.0 → vibesai_api-1.4.2}/VibesAI_api.egg-info/dependency_links.txt +0 -0
- {vibesai_api-1.4.0 → vibesai_api-1.4.2}/VibesAI_api.egg-info/entry_points.txt +0 -0
- {vibesai_api-1.4.0 → vibesai_api-1.4.2}/VibesAI_api.egg-info/requires.txt +0 -0
- {vibesai_api-1.4.0 → vibesai_api-1.4.2}/VibesAI_api.egg-info/top_level.txt +0 -0
- {vibesai_api-1.4.0 → vibesai_api-1.4.2}/setup.cfg +0 -0
- {vibesai_api-1.4.0 → vibesai_api-1.4.2}/vibes_api/cli.py +0 -0
- {vibesai_api-1.4.0 → vibesai_api-1.4.2}/vibes_api/composition.py +0 -0
- {vibesai_api-1.4.0 → vibesai_api-1.4.2}/vibes_api/ingredients.py +0 -0
- {vibesai_api-1.4.0 → vibesai_api-1.4.2}/vibes_api/models.py +0 -0
|
File without changes
|
|
File without changes
|
|
@@ -42,9 +42,9 @@ class TestImports(unittest.TestCase):
|
|
|
42
42
|
for name in vibes_api.__all__:
|
|
43
43
|
self.assertTrue(hasattr(vibes_api, name), f"Missing export: {name}")
|
|
44
44
|
|
|
45
|
-
def
|
|
45
|
+
def test_version_is_1_4_2(self):
|
|
46
46
|
import vibes_api
|
|
47
|
-
self.assertEqual(vibes_api.__version__, "1.4.
|
|
47
|
+
self.assertEqual(vibes_api.__version__, "1.4.2")
|
|
48
48
|
|
|
49
49
|
def test_no_syntax_errors(self):
|
|
50
50
|
import vibes_api.client
|
|
@@ -264,6 +264,10 @@ class VibesClient:
|
|
|
264
264
|
|
|
265
265
|
Returns True if the session was successfully restored.
|
|
266
266
|
"""
|
|
267
|
+
# Don't retry re-login if we're already in the middle of one
|
|
268
|
+
if self._session_expired:
|
|
269
|
+
return False
|
|
270
|
+
|
|
267
271
|
self._session_expired = True
|
|
268
272
|
|
|
269
273
|
if self.on_session_expired:
|
|
@@ -272,9 +276,10 @@ class VibesClient:
|
|
|
272
276
|
except Exception:
|
|
273
277
|
pass
|
|
274
278
|
|
|
275
|
-
if self.auto_relogin:
|
|
279
|
+
if self.auto_relogin and self.auth_meta_cookies:
|
|
276
280
|
new_cookie = self._attempt_oidc_relogin()
|
|
277
281
|
if new_cookie:
|
|
282
|
+
# _set_cookie resets _session_expired to False
|
|
278
283
|
self._set_cookie(new_cookie)
|
|
279
284
|
if self.on_cookie_refresh:
|
|
280
285
|
try:
|
|
@@ -283,33 +288,31 @@ class VibesClient:
|
|
|
283
288
|
pass
|
|
284
289
|
return True
|
|
285
290
|
|
|
291
|
+
# Reset the flag so future 401s can attempt re-login again
|
|
292
|
+
self._session_expired = False
|
|
286
293
|
return False
|
|
287
294
|
|
|
288
295
|
def _attempt_oidc_relogin(self) -> Optional[str]:
|
|
289
296
|
"""Attempt to re-login via the OIDC flow using auth.meta.com cookies.
|
|
290
297
|
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
2. auth.meta.com/oidc → gets authorization code (using auth cookies)
|
|
294
|
-
3. auth.meta.ai/ecto → exchanges code for vibes.ai callback URL
|
|
295
|
-
4. vibes.ai/api/meta-oidc/callback → creates new session
|
|
296
|
-
|
|
297
|
-
Requires ``auth_meta_cookies`` to be set (auth.meta.com cookies).
|
|
298
|
+
Follows the full OIDC redirect chain using requests.get() (not Session)
|
|
299
|
+
to avoid cookie/header interference between steps.
|
|
298
300
|
|
|
299
301
|
Returns the new meta_session cookie value, or None if re-login failed.
|
|
300
302
|
"""
|
|
301
303
|
if not self.auth_meta_cookies:
|
|
302
304
|
return None
|
|
303
305
|
|
|
306
|
+
ua = "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Safari/537.36"
|
|
307
|
+
|
|
304
308
|
for attempt in range(3):
|
|
305
309
|
try:
|
|
306
|
-
# Step 1: Start OIDC flow at vibes.ai
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
"User-Agent":
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
r1 = s1.get(f"{self.base_url}/api/meta-oidc/start", allow_redirects=False, timeout=15)
|
|
310
|
+
# Step 1: Start OIDC flow at vibes.ai
|
|
311
|
+
r1 = requests.get(
|
|
312
|
+
f"{self.base_url}/api/meta-oidc/start",
|
|
313
|
+
headers={"User-Agent": ua, "Cookie": "cookie_ack=true"},
|
|
314
|
+
allow_redirects=False, timeout=15,
|
|
315
|
+
)
|
|
313
316
|
if r1.status_code not in (302, 307):
|
|
314
317
|
if attempt < 2:
|
|
315
318
|
time.sleep(5)
|
|
@@ -321,70 +324,68 @@ class VibesClient:
|
|
|
321
324
|
|
|
322
325
|
# Extract oauth_csrf_token from Set-Cookie
|
|
323
326
|
csrf_token = None
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
if part.startswith("oauth_csrf_token="):
|
|
328
|
-
csrf_token = part[len("oauth_csrf_token="):]
|
|
327
|
+
for part in r1.headers.get("Set-Cookie", "").split(";"):
|
|
328
|
+
if part.strip().startswith("oauth_csrf_token="):
|
|
329
|
+
csrf_token = part.strip()[len("oauth_csrf_token="):]
|
|
329
330
|
break
|
|
330
331
|
|
|
331
|
-
# Step 2: auth.meta.com
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
"User-Agent":
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
r2 = s2.get(redirect_url, allow_redirects=False, timeout=15)
|
|
332
|
+
# Step 2: auth.meta.com (with auth.meta.com cookies only)
|
|
333
|
+
r2 = requests.get(
|
|
334
|
+
redirect_url,
|
|
335
|
+
headers={"User-Agent": ua, "Cookie": self.auth_meta_cookies},
|
|
336
|
+
allow_redirects=False, timeout=15,
|
|
337
|
+
)
|
|
338
338
|
if r2.status_code not in (302, 307):
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
continue
|
|
339
|
+
# 400 = auth.meta.com rate limited or cookies expired
|
|
340
|
+
# Don't retry — makes rate limiting worse
|
|
342
341
|
return None
|
|
343
342
|
redirect2 = r2.headers.get("Location", "")
|
|
344
343
|
if not redirect2 or "code=" not in redirect2:
|
|
345
344
|
return None
|
|
346
345
|
|
|
347
|
-
# Step 3: auth.meta.ai/ecto (code exchange)
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
"User-Agent":
|
|
351
|
-
|
|
352
|
-
|
|
346
|
+
# Step 3: auth.meta.ai/ecto (code exchange)
|
|
347
|
+
r3 = requests.get(
|
|
348
|
+
redirect2,
|
|
349
|
+
headers={"User-Agent": ua},
|
|
350
|
+
allow_redirects=False, timeout=15,
|
|
351
|
+
)
|
|
353
352
|
if r3.status_code not in (302, 307):
|
|
354
353
|
return None
|
|
355
354
|
redirect3 = r3.headers.get("Location", "")
|
|
356
355
|
if not redirect3 or "vibes.ai" not in redirect3:
|
|
357
356
|
return None
|
|
358
357
|
|
|
359
|
-
# Step 4: vibes.ai callback
|
|
360
|
-
|
|
361
|
-
s4.headers.update({
|
|
362
|
-
"User-Agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Safari/537.36",
|
|
363
|
-
})
|
|
364
|
-
callback_cookie = f"meta_session={self._current_meta_session};cookie_ack=true"
|
|
358
|
+
# Step 4: vibes.ai callback (CSRF token only, no old session)
|
|
359
|
+
callback_cookie = "cookie_ack=true"
|
|
365
360
|
if csrf_token:
|
|
366
361
|
callback_cookie += f";oauth_csrf_token={csrf_token}"
|
|
367
|
-
|
|
368
|
-
|
|
362
|
+
r4 = requests.get(
|
|
363
|
+
redirect3,
|
|
364
|
+
headers={"User-Agent": ua, "Cookie": callback_cookie},
|
|
365
|
+
allow_redirects=False, timeout=15,
|
|
366
|
+
)
|
|
367
|
+
|
|
368
|
+
# Check Set-Cookie for new meta_session
|
|
369
|
+
set_cookie = r4.headers.get("Set-Cookie", "").replace(",", ";")
|
|
370
|
+
for part in set_cookie.split(";"):
|
|
371
|
+
part = part.strip()
|
|
372
|
+
if part.startswith("meta_session="):
|
|
373
|
+
val = part[len("meta_session="):]
|
|
374
|
+
if val and val != "deleted" and val != self._current_meta_session:
|
|
375
|
+
return val
|
|
369
376
|
|
|
370
|
-
# Step 5: Follow final redirect
|
|
371
|
-
r5 = None
|
|
377
|
+
# Step 5: Follow final redirect if no cookie in step 4
|
|
372
378
|
final_redirect = r4.headers.get("Location", "")
|
|
373
379
|
if final_redirect and "error=" not in final_redirect:
|
|
374
380
|
if not final_redirect.startswith("http"):
|
|
375
381
|
final_redirect = f"{self.base_url}{final_redirect}"
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
for resp in responses:
|
|
384
|
-
set_cookie = resp.headers.get("Set-Cookie", "")
|
|
385
|
-
# Multiple cookies are separated by comma — replace with semicolon for parsing
|
|
386
|
-
set_cookie = set_cookie.replace(",", ";")
|
|
387
|
-
for part in set_cookie.split(";"):
|
|
382
|
+
r5 = requests.get(
|
|
383
|
+
final_redirect,
|
|
384
|
+
headers={"User-Agent": ua, "Cookie": "cookie_ack=true"},
|
|
385
|
+
allow_redirects=True, timeout=15,
|
|
386
|
+
)
|
|
387
|
+
set_cookie_5 = r5.headers.get("Set-Cookie", "").replace(",", ";")
|
|
388
|
+
for part in set_cookie_5.split(";"):
|
|
388
389
|
part = part.strip()
|
|
389
390
|
if part.startswith("meta_session="):
|
|
390
391
|
val = part[len("meta_session="):]
|
|
@@ -514,9 +515,10 @@ class VibesClient:
|
|
|
514
515
|
except VibesAPIError as e:
|
|
515
516
|
if e.status == 401 and not self._session_expired:
|
|
516
517
|
if self._handle_401():
|
|
517
|
-
# Session was restored — retry the request
|
|
518
|
+
# Session was restored — retry the request ONCE
|
|
518
519
|
resp = self.session.get(self._url(path), params=params, timeout=self.timeout, **kw)
|
|
519
520
|
return self._check(resp)
|
|
521
|
+
# Re-login failed or not enabled — raise the original error
|
|
520
522
|
raise
|
|
521
523
|
|
|
522
524
|
def _post(self, path: str, json_body: Optional[dict] = None, **kw) -> dict:
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|