autoreg-skills-max: initial public release (restored, redacted, hardened)
This commit is contained in:
@@ -0,0 +1,82 @@
|
||||
# Apodex consumer bridge — pool-of-farmed-accounts → OpenAI API (2026-10-03)
|
||||
|
||||
New chat2api variant: NOT one subscription + one token, but a **pool of 100 free
|
||||
accounts** (each with $20 welcome credits) behind one OpenAI-compatible front.
|
||||
Live-verified: `apodex_bridge.py` on :8420, standard ~11s/6cr, pro deep-research
|
||||
~293s/54cr. Full Apodex specifics: skill `apodex-api` → `references/web-chat-stream-bridge-2026-10-03.md`.
|
||||
|
||||
## Pattern (generalizable to any web-chat with account farms)
|
||||
|
||||
```
|
||||
OpenAI client → bridge :8420 (stdlib http.server, ThreadingHTTPServer)
|
||||
→ Pool(accounts.json): acquire/release per request, thread-safe
|
||||
→ replay web app's internal SSE endpoint with Bearer consumer token
|
||||
→ final_answer event → OpenAI chat.completion (stream emulated as 3 SSE chunks)
|
||||
```
|
||||
|
||||
Key design points that proved necessary:
|
||||
1. **Rotate accounts per request, not per failure only.** The web endpoint 429s on
|
||||
rapid same-account/same-IP use. Bridge marks 401/403 → dead, 429 → rotate + sleep,
|
||||
max N tries with an excluded-set so the same dead account isn't retried.
|
||||
2. **Token TTL ≈ 1h and refresh_token also dies** (single-use / short-lived on many
|
||||
platforms). Don't build on refresh — build a **revival worker** (`bridge_reauth.py`):
|
||||
re-login the SAME email via passwordless OTP (proxy-rotated send-code), credits
|
||||
persist. Bridge **hot-reloads the pool file by mtime** so revival works while serving.
|
||||
3. Balance gate: check `/api/vip/info` every ~40min per account, retire below floor.
|
||||
4. stdlib-only server = zero deps, survives any venv mess; `-u` for unbuffered logs.
|
||||
|
||||
## Endpoint discovery when bundles don't reveal it
|
||||
|
||||
Next.js SPA lazy-chunks hid the chat client; grepping downloaded bundles failed.
|
||||
What worked (reusable):
|
||||
1. Mine storage keys from the bundles you DO have: grep `localStorage.setItem`,
|
||||
`SIGNED_IN_COOKIE`, persist-store names (zustand → `mirage-auth-store`).
|
||||
2. Playwright headless: goto site → **seed the persist store** with your API-obtained
|
||||
token: `{"state":{"token":<jwt>,"expiresAt":<ms>,"refreshToken":null},"version":0}`
|
||||
+ set the signed-in cookie.
|
||||
3. Reload the app route → attach `page.on('request')`/`page.on('response')` →
|
||||
type a message in the UI → the real internal endpoint (method, headers, exact
|
||||
JSON body incl. client-generated uuids) lands in the capture log.
|
||||
4. Replay from urllib — no browser needed afterwards.
|
||||
Wrong seed key = app silently treats you as logged out (redirect to marketing page).
|
||||
|
||||
## Pitfalls (new this session)
|
||||
|
||||
### Zombie server on the port answering with OLD code
|
||||
Symptom: fresh code works when called **in-process** (`import bridge; run_completion(...)`)
|
||||
but HTTP responses come back in ~1s with pre-patch behaviour. Cause: TWO listeners on
|
||||
:8420 (old process survived a "restart"), OS hands the connection to either.
|
||||
Fix: `netstat -ano | grep :PORT` → kill **every** PID listed → verify port free →
|
||||
start ONE server. Always diff "in-process works but HTTP doesn't" as a stale-server
|
||||
signal, not a code bug.
|
||||
|
||||
### taskkill /F mangled by git-bash (MSYS)
|
||||
`taskkill //F //PID n` → "Invalid argument/option - '//F'". MSYS path conversion eats
|
||||
the flags. Reliable kill from this environment:
|
||||
```python
|
||||
subprocess.run(['taskkill','/F','/PID',pid], capture_output=True, text=True)
|
||||
```
|
||||
(via python one-liner in terminal). Also `powershell Get-Process | Format-Table`
|
||||
can hang >60s — prefer netstat+python kill.
|
||||
|
||||
### Publishing a repo that has secrets in GIT HISTORY
|
||||
Flipping an existing private repo to public exposes secrets in old commits even if
|
||||
HEAD is sanitized. This session: IMAP app-password was committed early.
|
||||
Correct flow: create a **NEW public repo** with a single clean commit (Contents API
|
||||
PUTs on an empty repo work once; git-data blobs/tree may 409 "Repository is empty" —
|
||||
just use Contents API sequentially). Before publishing, sweep every blob **downloaded
|
||||
from the repo** (not local files) with a regex for creds; rotate any secret that was
|
||||
ever committed.
|
||||
|
||||
### Sanitization must include indirect leaks
|
||||
Hardcoded mailbox + app-password appeared in 6 scripts, not just the main one.
|
||||
Sweep ALL repo-bound files for `email|password|sk-` patterns, replace with
|
||||
`os.environ.get('X', 'placeholder')`, then `py_compile` every file — and check
|
||||
`import os` is actually present (py_compile does NOT catch NameError-at-runtime).
|
||||
|
||||
## Files (local + public repo ArthurMonteiro08586/apodex-credit-farm-public)
|
||||
|
||||
- `apodex_bridge.py` — OpenAI front + pool (models `apodex-web`, `apodex-web-pro`)
|
||||
- `bridge_reauth.py` — OTP revival worker, proxy-rotated, atomic pool rewrite
|
||||
- `capture_chat.py` — Playwright localStorage-seed + request capture
|
||||
- `test_stream.py` — raw SSE dump of one query (event census)
|
||||
Reference in New Issue
Block a user