devlinker 1.4.0__tar.gz → 1.4.1__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.
Files changed (34) hide show
  1. {devlinker-1.4.0/devlinker.egg-info → devlinker-1.4.1}/PKG-INFO +98 -46
  2. {devlinker-1.4.0 → devlinker-1.4.1}/README.md +96 -45
  3. devlinker-1.4.1/devlinker/config.py +17 -0
  4. {devlinker-1.4.0 → devlinker-1.4.1}/devlinker/detector_ai.py +6 -1
  5. devlinker-1.4.1/devlinker/main.py +710 -0
  6. {devlinker-1.4.0 → devlinker-1.4.1}/devlinker/proxy.py +114 -26
  7. {devlinker-1.4.0 → devlinker-1.4.1}/devlinker/runner.py +77 -27
  8. {devlinker-1.4.0 → devlinker-1.4.1/devlinker.egg-info}/PKG-INFO +98 -46
  9. {devlinker-1.4.0 → devlinker-1.4.1}/devlinker.egg-info/requires.txt +1 -0
  10. {devlinker-1.4.0 → devlinker-1.4.1}/pyproject.toml +2 -1
  11. devlinker-1.4.0/devlinker/config.py +0 -8
  12. devlinker-1.4.0/devlinker/main.py +0 -399
  13. {devlinker-1.4.0 → devlinker-1.4.1}/LICENSE +0 -0
  14. {devlinker-1.4.0 → devlinker-1.4.1}/MANIFEST.in +0 -0
  15. {devlinker-1.4.0 → devlinker-1.4.1}/devlinker/__init__.py +0 -0
  16. {devlinker-1.4.0 → devlinker-1.4.1}/devlinker/detection_state.py +0 -0
  17. {devlinker-1.4.0 → devlinker-1.4.1}/devlinker/detector.py +0 -0
  18. {devlinker-1.4.0 → devlinker-1.4.1}/devlinker/devlinker_loader_instant.html +0 -0
  19. {devlinker-1.4.0 → devlinker-1.4.1}/devlinker/devlinker_loader_snippet.html +0 -0
  20. {devlinker-1.4.0 → devlinker-1.4.1}/devlinker/doctor.py +0 -0
  21. {devlinker-1.4.0 → devlinker-1.4.1}/devlinker/fix.py +0 -0
  22. {devlinker-1.4.0 → devlinker-1.4.1}/devlinker/fixer.py +0 -0
  23. {devlinker-1.4.0 → devlinker-1.4.1}/devlinker/global_state.py +0 -0
  24. {devlinker-1.4.0 → devlinker-1.4.1}/devlinker/inspect.py +0 -0
  25. {devlinker-1.4.0 → devlinker-1.4.1}/devlinker/logger.py +0 -0
  26. {devlinker-1.4.0 → devlinker-1.4.1}/devlinker/monitor.py +0 -0
  27. {devlinker-1.4.0 → devlinker-1.4.1}/devlinker/share.py +0 -0
  28. {devlinker-1.4.0 → devlinker-1.4.1}/devlinker/tunnel.py +0 -0
  29. {devlinker-1.4.0 → devlinker-1.4.1}/devlinker.egg-info/SOURCES.txt +0 -0
  30. {devlinker-1.4.0 → devlinker-1.4.1}/devlinker.egg-info/dependency_links.txt +0 -0
  31. {devlinker-1.4.0 → devlinker-1.4.1}/devlinker.egg-info/entry_points.txt +0 -0
  32. {devlinker-1.4.0 → devlinker-1.4.1}/devlinker.egg-info/top_level.txt +0 -0
  33. {devlinker-1.4.0 → devlinker-1.4.1}/setup.cfg +0 -0
  34. {devlinker-1.4.0 → devlinker-1.4.1}/setup.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: devlinker
3
- Version: 1.4.0
3
+ Version: 1.4.1
4
4
  Summary: A lightweight proxy that combines your frontend and backend into one link for easy development and sharing.
5
5
  Author-email: Mani <mani1028@users.noreply.github.com>
6
6
  Requires-Python: >=3.7
@@ -13,19 +13,24 @@ Requires-Dist: httpx
13
13
  Requires-Dist: pyngrok
14
14
  Requires-Dist: qrcode[pil]
15
15
  Requires-Dist: requests
16
+ Requires-Dist: rich
16
17
  Requires-Dist: uvicorn
17
18
  Requires-Dist: websockets
18
19
  Dynamic: license-file
19
20
 
20
21
  # Dev Linker
21
22
 
22
- Dev Linker runs frontend and backend dev servers, proxies both through a single local port (8000), and creates a single public URL via Cloudflare or ngrok.
23
+ Dev Linker starts your local development stack and routes frontend and backend traffic through one proxy URL, with optional LAN and public sharing.
23
24
 
24
25
 
25
26
  ## Features
26
27
 
27
28
  - 🚀 **Unified Dev Proxy:** Combines frontend (Vite/React) and backend (FastAPI/Flask/Node/Docker) into a single local and public URL.
28
29
  - 🔍 **Auto Detection:** Detects frontend/backend ports, runtime, Docker containers, and Vite servers automatically.
30
+ - 📡 **Debug Request Logger:** Live API traffic lines (method, path, status, latency) only in debug mode.
31
+ - 🧩 **Backend-Only Mode:** If no frontend is detected, DevLinker still runs and forwards all traffic to backend.
32
+ - 🔁 **Auto API URL Sync:** Updates `frontend/.env.local` with `VITE_API_URL=http://localhost:<proxy-port>` using a managed block.
33
+ - 🛡️ **Proxy CORS + Preflight:** Handles common CORS/preflight behavior at the proxy layer, including credential-safe Origin handling.
29
34
  - 🧠 **Smart Detection & Doctor:** Real-time request analysis, backend intelligence, log analyzer, and `devlinker doctor` for instant diagnostics.
30
35
  - 🛡️ **Auto-Fix Engine:** `devlinker fix` applies safe fixes (like VITE_API_URL) and suggests code changes.
31
36
  - 🌍 **Public Sharing:** Share your local dev environment instantly with `--url` (startup) or `devlinker share` (runtime, no restart).
@@ -62,6 +67,7 @@ If DevLinker helps you ship faster, consider supporting the project:
62
67
  - `devlinker --no-lan` — Hide WLAN sharing URL
63
68
  - `devlinker --interactive-backend` — Prompt to choose backend if multiple found
64
69
  - `devlinker --proxy-port 18000` — Use custom proxy port
70
+ - `devlinker --debug` — Enable debug mode (turns on live API request logger)
65
71
  - `devlinker --version` — Show version
66
72
 
67
73
  ## Project Structure
@@ -88,6 +94,12 @@ For local development:
88
94
  pip install .
89
95
  ```
90
96
 
97
+ For editable local development:
98
+
99
+ ```bash
100
+ pip install -e .
101
+ ```
102
+
91
103
  After publishing to PyPI:
92
104
 
93
105
  ```bash
@@ -100,34 +112,47 @@ pip install devlinker
100
112
  devlinker
101
113
  ```
102
114
 
103
- Typical startup output:
115
+ Direct module run (without installing entrypoint script):
116
+
117
+ ```bash
118
+ python -m devlinker.main
119
+ ```
120
+
121
+ Typical startup output (TTY with Rich available):
122
+
123
+ ```text
124
+ ╭─────────────────────────────╮
125
+ │ ♾️ DevLinker v1.4.1 │
126
+ │ Smart Local Dev Environment │
127
+ ╰─────────────────────────────╯
128
+
129
+ ✔ Detecting project...
130
+ ⏳ Booting local services...
131
+
132
+ ╭───────── DevLinker Ready ─────────╮
133
+ │ Proxy http://localhost:8001 │
134
+ │ WLAN http://192.168.1.3:8001 │
135
+ │ Public disabled (use --url) │
136
+ ╰───────────────────────────────────╯
137
+
138
+ ✨ Ready in 5.5s
139
+ Powered by DevLinker 🚀
140
+ ```
141
+
142
+ Enable debug mode with live API request logging:
143
+
144
+ ```bash
145
+ devlinker --debug
146
+ ```
147
+
148
+ Debug mode request logger sample:
104
149
 
105
150
  ```text
106
- Dev Linker v1.2.2
107
-
108
- [INFO] Mode: Auto (FastAPI async proxy + Docker detection)
109
- [INFO] Booting local services...
110
- [INFO] Detecting frontend/backend ports...
111
- [OK] Frontend -> 5173
112
- [OK] Backend -> 5000
113
-
114
- [OK] Proxy ready at http://localhost:8000
115
-
116
- [OK] Tunnel provider: Cloudflare
117
- [OK] Public URL:
118
- https://xxxx.trycloudflare.com
119
- Tip: Press Ctrl+Click to open link
120
-
121
- [INFO] Share this link with collaborators.
122
-
123
- DevLinker Ready (in 2.4s)
124
- Frontend: http://localhost:5173
125
- Backend: http://localhost:5000
126
- Access Links:
127
- Local: http://localhost:8000
128
- WLAN: http://192.168.1.5:8000
129
- Public: https://xxxx.trycloudflare.com
130
- Tip: Press Ctrl+Click to open link
151
+ 🛠 Debug mode enabled: live API request logger is ON
152
+
153
+ 📡 Requests (Live)
154
+ GET /api/users 200 45ms
155
+ POST /api/login 401 120ms
131
156
  ```
132
157
 
133
158
  Version check:
@@ -160,15 +185,6 @@ devlinker --docker
160
185
  By default, DevLinker starts **fast local proxy only** (no tunnel). To enable a public tunnel, use the `--url` flag:
161
186
 
162
187
 
163
- ```bash
164
- devlinker --url
165
- ```
166
-
167
- In your terminal output, you'll see:
168
-
169
-
170
- URL, run:
171
-
172
188
  ```bash
173
189
  devlinker --url
174
190
  ```
@@ -177,11 +193,11 @@ This will start the proxy and open a public tunnel (Cloudflare or ngrok). The ou
177
193
 
178
194
  ```text
179
195
  🌍 Enabling public tunnel...
180
- [OK] Tunnel provider: Cloudflare
181
- [OK] Public URL:
196
+ Tunnel provider: Cloudflare
197
+ Public URL:
182
198
  https://xxxx.trycloudflare.com
183
- Tip: Press Ctrl+Click to open link
184
- [INFO] Share this link with collaborators.
199
+ Tip: Ctrl+Click to open link
200
+ Share this link with collaborators.
185
201
  ```
186
202
 
187
203
  To force tunnel off (even if --url is passed):
@@ -241,13 +257,11 @@ devlinker --frontend 5173 --backend 5000 --proxy-port 18000
241
257
  Default behavior also tries fallback ports automatically when 8000 is busy:
242
258
 
243
259
  ```text
244
- [WARN] Port 8000 in use
245
- [INFO] Using proxy port: 8001
260
+ Port 8000 in use
261
+ Using proxy port: 8001
246
262
  ```
247
263
 
248
- - 8001
249
- - 8002
250
- - 18000
264
+ By default it scans the next 10 ports after the requested one, then tries `18000`.
251
265
 
252
266
  Frontend detection behavior:
253
267
 
@@ -266,6 +280,41 @@ fetch("/api/endpoint")
266
280
 
267
281
  Do not hardcode backend host URLs in frontend code.
268
282
 
283
+ DevLinker also writes/updates a managed block in `frontend/.env.local`:
284
+
285
+ ```env
286
+ # devlinker-managed:start
287
+ VITE_API_URL=http://localhost:8001
288
+ # devlinker-managed:end
289
+ ```
290
+
291
+ This keeps frontend API calls consistently routed through the proxy.
292
+
293
+ Use the proxy URL as your single entry point during development:
294
+
295
+ ```text
296
+ http://localhost:<proxy-port>
297
+ ```
298
+
299
+ Avoid direct backend calls like `http://localhost:5000` from browser-facing code.
300
+
301
+ ## Configuration File
302
+
303
+ DevLinker loads config from the first file found in this order:
304
+
305
+ 1. `devlinker.yaml`
306
+ 2. `devlinker.yml`
307
+ 3. `devlinker.json`
308
+
309
+ Example:
310
+
311
+ ```yaml
312
+ frontend: 5173
313
+ backend: 5000
314
+ proxy_port: 8001
315
+ tunnel: false
316
+ ```
317
+
269
318
  ## Backend Auto-Detection
270
319
 
271
320
  Backend port detection runs in this order:
@@ -321,12 +370,15 @@ For containerized Flask backends, ensure:
321
370
 
322
371
  - runner.py expects frontend project in frontend and Python app in backend/app.py.
323
372
  - If those paths do not exist, Dev Linker skips launch and only tries to detect already-running services.
373
+ - If frontend is missing but backend is available, DevLinker continues in backend-only mode.
324
374
  - Tunnel selection order is: cloudflared (TryCloudflare), then ngrok.
325
375
  - If cloudflared is unavailable and ngrok is not configured, Dev Linker prints one-time setup guidance.
326
376
  - You may need to set ngrok auth once on your machine using ngrok config add-authtoken <token>.
327
377
  - Dev Linker prints a public URL with `ngrok-skip-browser-warning=true` only when ngrok is used.
328
378
  - Startup output includes selected tunnel provider (`cloudflare` or `ngrok`).
329
379
  - Proxy layer now supports WebSocket upgrades, including Vite HMR over shared links.
380
+ - Proxy handles common CORS/preflight behavior and adds camera/mic permissions policy headers.
381
+ - Live API request logging is disabled by default and only enabled with `devlinker --debug`.
330
382
  - Proxy listens on `0.0.0.0` and can print a WLAN URL for same-network sharing.
331
383
  - If WLAN access fails on Windows, allow the proxy port in firewall and confirm devices are on the same network.
332
384
 
@@ -1,12 +1,16 @@
1
1
  # Dev Linker
2
2
 
3
- Dev Linker runs frontend and backend dev servers, proxies both through a single local port (8000), and creates a single public URL via Cloudflare or ngrok.
3
+ Dev Linker starts your local development stack and routes frontend and backend traffic through one proxy URL, with optional LAN and public sharing.
4
4
 
5
5
 
6
6
  ## Features
7
7
 
8
8
  - 🚀 **Unified Dev Proxy:** Combines frontend (Vite/React) and backend (FastAPI/Flask/Node/Docker) into a single local and public URL.
9
9
  - 🔍 **Auto Detection:** Detects frontend/backend ports, runtime, Docker containers, and Vite servers automatically.
10
+ - 📡 **Debug Request Logger:** Live API traffic lines (method, path, status, latency) only in debug mode.
11
+ - 🧩 **Backend-Only Mode:** If no frontend is detected, DevLinker still runs and forwards all traffic to backend.
12
+ - 🔁 **Auto API URL Sync:** Updates `frontend/.env.local` with `VITE_API_URL=http://localhost:<proxy-port>` using a managed block.
13
+ - 🛡️ **Proxy CORS + Preflight:** Handles common CORS/preflight behavior at the proxy layer, including credential-safe Origin handling.
10
14
  - 🧠 **Smart Detection & Doctor:** Real-time request analysis, backend intelligence, log analyzer, and `devlinker doctor` for instant diagnostics.
11
15
  - 🛡️ **Auto-Fix Engine:** `devlinker fix` applies safe fixes (like VITE_API_URL) and suggests code changes.
12
16
  - 🌍 **Public Sharing:** Share your local dev environment instantly with `--url` (startup) or `devlinker share` (runtime, no restart).
@@ -43,6 +47,7 @@ If DevLinker helps you ship faster, consider supporting the project:
43
47
  - `devlinker --no-lan` — Hide WLAN sharing URL
44
48
  - `devlinker --interactive-backend` — Prompt to choose backend if multiple found
45
49
  - `devlinker --proxy-port 18000` — Use custom proxy port
50
+ - `devlinker --debug` — Enable debug mode (turns on live API request logger)
46
51
  - `devlinker --version` — Show version
47
52
 
48
53
  ## Project Structure
@@ -69,6 +74,12 @@ For local development:
69
74
  pip install .
70
75
  ```
71
76
 
77
+ For editable local development:
78
+
79
+ ```bash
80
+ pip install -e .
81
+ ```
82
+
72
83
  After publishing to PyPI:
73
84
 
74
85
  ```bash
@@ -81,34 +92,47 @@ pip install devlinker
81
92
  devlinker
82
93
  ```
83
94
 
84
- Typical startup output:
95
+ Direct module run (without installing entrypoint script):
96
+
97
+ ```bash
98
+ python -m devlinker.main
99
+ ```
100
+
101
+ Typical startup output (TTY with Rich available):
102
+
103
+ ```text
104
+ ╭─────────────────────────────╮
105
+ │ ♾️ DevLinker v1.4.1 │
106
+ │ Smart Local Dev Environment │
107
+ ╰─────────────────────────────╯
108
+
109
+ ✔ Detecting project...
110
+ ⏳ Booting local services...
111
+
112
+ ╭───────── DevLinker Ready ─────────╮
113
+ │ Proxy http://localhost:8001 │
114
+ │ WLAN http://192.168.1.3:8001 │
115
+ │ Public disabled (use --url) │
116
+ ╰───────────────────────────────────╯
117
+
118
+ ✨ Ready in 5.5s
119
+ Powered by DevLinker 🚀
120
+ ```
121
+
122
+ Enable debug mode with live API request logging:
123
+
124
+ ```bash
125
+ devlinker --debug
126
+ ```
127
+
128
+ Debug mode request logger sample:
85
129
 
86
130
  ```text
87
- Dev Linker v1.2.2
88
-
89
- [INFO] Mode: Auto (FastAPI async proxy + Docker detection)
90
- [INFO] Booting local services...
91
- [INFO] Detecting frontend/backend ports...
92
- [OK] Frontend -> 5173
93
- [OK] Backend -> 5000
94
-
95
- [OK] Proxy ready at http://localhost:8000
96
-
97
- [OK] Tunnel provider: Cloudflare
98
- [OK] Public URL:
99
- https://xxxx.trycloudflare.com
100
- Tip: Press Ctrl+Click to open link
101
-
102
- [INFO] Share this link with collaborators.
103
-
104
- DevLinker Ready (in 2.4s)
105
- Frontend: http://localhost:5173
106
- Backend: http://localhost:5000
107
- Access Links:
108
- Local: http://localhost:8000
109
- WLAN: http://192.168.1.5:8000
110
- Public: https://xxxx.trycloudflare.com
111
- Tip: Press Ctrl+Click to open link
131
+ 🛠 Debug mode enabled: live API request logger is ON
132
+
133
+ 📡 Requests (Live)
134
+ GET /api/users 200 45ms
135
+ POST /api/login 401 120ms
112
136
  ```
113
137
 
114
138
  Version check:
@@ -141,15 +165,6 @@ devlinker --docker
141
165
  By default, DevLinker starts **fast local proxy only** (no tunnel). To enable a public tunnel, use the `--url` flag:
142
166
 
143
167
 
144
- ```bash
145
- devlinker --url
146
- ```
147
-
148
- In your terminal output, you'll see:
149
-
150
-
151
- URL, run:
152
-
153
168
  ```bash
154
169
  devlinker --url
155
170
  ```
@@ -158,11 +173,11 @@ This will start the proxy and open a public tunnel (Cloudflare or ngrok). The ou
158
173
 
159
174
  ```text
160
175
  🌍 Enabling public tunnel...
161
- [OK] Tunnel provider: Cloudflare
162
- [OK] Public URL:
176
+ Tunnel provider: Cloudflare
177
+ Public URL:
163
178
  https://xxxx.trycloudflare.com
164
- Tip: Press Ctrl+Click to open link
165
- [INFO] Share this link with collaborators.
179
+ Tip: Ctrl+Click to open link
180
+ Share this link with collaborators.
166
181
  ```
167
182
 
168
183
  To force tunnel off (even if --url is passed):
@@ -222,13 +237,11 @@ devlinker --frontend 5173 --backend 5000 --proxy-port 18000
222
237
  Default behavior also tries fallback ports automatically when 8000 is busy:
223
238
 
224
239
  ```text
225
- [WARN] Port 8000 in use
226
- [INFO] Using proxy port: 8001
240
+ Port 8000 in use
241
+ Using proxy port: 8001
227
242
  ```
228
243
 
229
- - 8001
230
- - 8002
231
- - 18000
244
+ By default it scans the next 10 ports after the requested one, then tries `18000`.
232
245
 
233
246
  Frontend detection behavior:
234
247
 
@@ -247,6 +260,41 @@ fetch("/api/endpoint")
247
260
 
248
261
  Do not hardcode backend host URLs in frontend code.
249
262
 
263
+ DevLinker also writes/updates a managed block in `frontend/.env.local`:
264
+
265
+ ```env
266
+ # devlinker-managed:start
267
+ VITE_API_URL=http://localhost:8001
268
+ # devlinker-managed:end
269
+ ```
270
+
271
+ This keeps frontend API calls consistently routed through the proxy.
272
+
273
+ Use the proxy URL as your single entry point during development:
274
+
275
+ ```text
276
+ http://localhost:<proxy-port>
277
+ ```
278
+
279
+ Avoid direct backend calls like `http://localhost:5000` from browser-facing code.
280
+
281
+ ## Configuration File
282
+
283
+ DevLinker loads config from the first file found in this order:
284
+
285
+ 1. `devlinker.yaml`
286
+ 2. `devlinker.yml`
287
+ 3. `devlinker.json`
288
+
289
+ Example:
290
+
291
+ ```yaml
292
+ frontend: 5173
293
+ backend: 5000
294
+ proxy_port: 8001
295
+ tunnel: false
296
+ ```
297
+
250
298
  ## Backend Auto-Detection
251
299
 
252
300
  Backend port detection runs in this order:
@@ -302,12 +350,15 @@ For containerized Flask backends, ensure:
302
350
 
303
351
  - runner.py expects frontend project in frontend and Python app in backend/app.py.
304
352
  - If those paths do not exist, Dev Linker skips launch and only tries to detect already-running services.
353
+ - If frontend is missing but backend is available, DevLinker continues in backend-only mode.
305
354
  - Tunnel selection order is: cloudflared (TryCloudflare), then ngrok.
306
355
  - If cloudflared is unavailable and ngrok is not configured, Dev Linker prints one-time setup guidance.
307
356
  - You may need to set ngrok auth once on your machine using ngrok config add-authtoken <token>.
308
357
  - Dev Linker prints a public URL with `ngrok-skip-browser-warning=true` only when ngrok is used.
309
358
  - Startup output includes selected tunnel provider (`cloudflare` or `ngrok`).
310
359
  - Proxy layer now supports WebSocket upgrades, including Vite HMR over shared links.
360
+ - Proxy handles common CORS/preflight behavior and adds camera/mic permissions policy headers.
361
+ - Live API request logging is disabled by default and only enabled with `devlinker --debug`.
311
362
  - Proxy listens on `0.0.0.0` and can print a WLAN URL for same-network sharing.
312
363
  - If WLAN access fails on Windows, allow the proxy port in firewall and confirm devices are on the same network.
313
364
 
@@ -0,0 +1,17 @@
1
+ import os
2
+ import json
3
+
4
+ import yaml
5
+
6
+ def load_config(config_path: str = "devlinker.yaml") -> dict:
7
+ candidates = [config_path, "devlinker.yml", "devlinker.json"]
8
+ selected = next((path for path in candidates if os.path.exists(path)), None)
9
+ if not selected:
10
+ return {}
11
+
12
+ with open(selected, "r", encoding="utf-8") as handle:
13
+ if selected.endswith(".json"):
14
+ data = json.load(handle)
15
+ else:
16
+ data = yaml.safe_load(handle)
17
+ return data or {}
@@ -1,16 +1,21 @@
1
1
  class DevLinkerAI:
2
2
  def analyze_failure(self, error_text):
3
+ lowered = error_text.lower()
3
4
  if "CORS" in error_text:
4
5
  return [
5
6
  "Frontend is calling backend directly",
6
7
  "Use /api/* instead of localhost:PORT"
7
8
  ]
8
9
  if "404" in error_text:
10
+ if " get / " in lowered or lowered.strip().startswith("get /"):
11
+ return []
12
+ if "/api" not in lowered:
13
+ return ["Route not found"]
9
14
  return [
10
15
  "Route not found",
11
16
  "Check if '/api' prefix is required"
12
17
  ]
13
- if "connection refused" in error_text.lower():
18
+ if "connection refused" in lowered:
14
19
  return [
15
20
  "Backend not reachable",
16
21
  "Ensure backend is running"