devlinker 1.3.8__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 (35) hide show
  1. {devlinker-1.3.8/devlinker.egg-info → devlinker-1.4.1}/PKG-INFO +111 -46
  2. {devlinker-1.3.8 → devlinker-1.4.1}/README.md +108 -45
  3. devlinker-1.4.1/devlinker/config.py +17 -0
  4. {devlinker-1.3.8 → devlinker-1.4.1}/devlinker/detector_ai.py +6 -1
  5. {devlinker-1.3.8 → devlinker-1.4.1}/devlinker/devlinker_loader_instant.html +20 -3
  6. {devlinker-1.3.8 → devlinker-1.4.1}/devlinker/devlinker_loader_snippet.html +42 -1
  7. devlinker-1.4.1/devlinker/main.py +710 -0
  8. {devlinker-1.3.8 → devlinker-1.4.1}/devlinker/proxy.py +170 -28
  9. {devlinker-1.3.8 → devlinker-1.4.1}/devlinker/runner.py +77 -27
  10. {devlinker-1.3.8 → devlinker-1.4.1/devlinker.egg-info}/PKG-INFO +111 -46
  11. devlinker-1.4.1/devlinker.egg-info/entry_points.txt +2 -0
  12. {devlinker-1.3.8 → devlinker-1.4.1}/devlinker.egg-info/requires.txt +2 -0
  13. {devlinker-1.3.8 → devlinker-1.4.1}/pyproject.toml +4 -2
  14. devlinker-1.3.8/devlinker/config.py +0 -8
  15. devlinker-1.3.8/devlinker/main.py +0 -304
  16. devlinker-1.3.8/devlinker.egg-info/entry_points.txt +0 -2
  17. {devlinker-1.3.8 → devlinker-1.4.1}/LICENSE +0 -0
  18. {devlinker-1.3.8 → devlinker-1.4.1}/MANIFEST.in +0 -0
  19. {devlinker-1.3.8 → devlinker-1.4.1}/devlinker/__init__.py +0 -0
  20. {devlinker-1.3.8 → devlinker-1.4.1}/devlinker/detection_state.py +0 -0
  21. {devlinker-1.3.8 → devlinker-1.4.1}/devlinker/detector.py +0 -0
  22. {devlinker-1.3.8 → devlinker-1.4.1}/devlinker/doctor.py +0 -0
  23. {devlinker-1.3.8 → devlinker-1.4.1}/devlinker/fix.py +0 -0
  24. {devlinker-1.3.8 → devlinker-1.4.1}/devlinker/fixer.py +0 -0
  25. {devlinker-1.3.8 → devlinker-1.4.1}/devlinker/global_state.py +0 -0
  26. {devlinker-1.3.8 → devlinker-1.4.1}/devlinker/inspect.py +0 -0
  27. {devlinker-1.3.8 → devlinker-1.4.1}/devlinker/logger.py +0 -0
  28. {devlinker-1.3.8 → devlinker-1.4.1}/devlinker/monitor.py +0 -0
  29. {devlinker-1.3.8 → devlinker-1.4.1}/devlinker/share.py +0 -0
  30. {devlinker-1.3.8 → devlinker-1.4.1}/devlinker/tunnel.py +0 -0
  31. {devlinker-1.3.8 → devlinker-1.4.1}/devlinker.egg-info/SOURCES.txt +0 -0
  32. {devlinker-1.3.8 → devlinker-1.4.1}/devlinker.egg-info/dependency_links.txt +0 -0
  33. {devlinker-1.3.8 → devlinker-1.4.1}/devlinker.egg-info/top_level.txt +0 -0
  34. {devlinker-1.3.8 → devlinker-1.4.1}/setup.cfg +0 -0
  35. {devlinker-1.3.8 → 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.3.8
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
@@ -11,20 +11,26 @@ Requires-Dist: docker
11
11
  Requires-Dist: fastapi
12
12
  Requires-Dist: httpx
13
13
  Requires-Dist: pyngrok
14
+ Requires-Dist: qrcode[pil]
14
15
  Requires-Dist: requests
16
+ Requires-Dist: rich
15
17
  Requires-Dist: uvicorn
16
18
  Requires-Dist: websockets
17
19
  Dynamic: license-file
18
20
 
19
21
  # Dev Linker
20
22
 
21
- 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.
22
24
 
23
25
 
24
26
  ## Features
25
27
 
26
28
  - 🚀 **Unified Dev Proxy:** Combines frontend (Vite/React) and backend (FastAPI/Flask/Node/Docker) into a single local and public URL.
27
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.
28
34
  - 🧠 **Smart Detection & Doctor:** Real-time request analysis, backend intelligence, log analyzer, and `devlinker doctor` for instant diagnostics.
29
35
  - 🛡️ **Auto-Fix Engine:** `devlinker fix` applies safe fixes (like VITE_API_URL) and suggests code changes.
30
36
  - 🌍 **Public Sharing:** Share your local dev environment instantly with `--url` (startup) or `devlinker share` (runtime, no restart).
@@ -35,9 +41,21 @@ Dev Linker runs frontend and backend dev servers, proxies both through a single
35
41
  - 🧪 **Runtime Smoke Test:** Built-in test for end-to-end proxy validation.
36
42
  - 🛠️ **Extensible:** Modular architecture for future SaaS, dashboard, and team features.
37
43
 
44
+ ## Support DevLinker
45
+
46
+ If DevLinker helps you ship faster, consider supporting the project:
47
+
48
+ > 💖 Support DevLinker
49
+ > [![UPI](https://img.shields.io/badge/UPI-devlinker%40upi-22c55e?style=for-the-badge)](upi://pay?pa=devlinker@upi&pn=DevLinker&cu=INR&tn=Support%20DevLinker%20Project%20🚀)
50
+ > [![Donate](https://img.shields.io/badge/Support-Scan%20or%20Pay-0ea5e9?style=for-the-badge)](upi://pay?pa=devlinker@upi&pn=DevLinker&cu=INR&tn=Support%20DevLinker%20Project%20🚀)
51
+
52
+ - 💖 UPI: devlinker@upi
53
+ - 🔗 UPI link: upi://pay?pa=devlinker@upi&pn=DevLinker&cu=INR&tn=Support%20DevLinker%20Project%20🚀
54
+
38
55
  ## CLI Commands & Options
39
56
 
40
57
  - `devlinker` — Start proxy (local only, fast)
58
+ - `devlinker support` — Show UPI support QR code in terminal
41
59
  - `devlinker --url` — Start with public tunnel (Cloudflare/ngrok)
42
60
  - `devlinker share` — Enable public tunnel at runtime (no restart)
43
61
  - `devlinker unshare` — Disable public tunnel at runtime
@@ -49,6 +67,7 @@ Dev Linker runs frontend and backend dev servers, proxies both through a single
49
67
  - `devlinker --no-lan` — Hide WLAN sharing URL
50
68
  - `devlinker --interactive-backend` — Prompt to choose backend if multiple found
51
69
  - `devlinker --proxy-port 18000` — Use custom proxy port
70
+ - `devlinker --debug` — Enable debug mode (turns on live API request logger)
52
71
  - `devlinker --version` — Show version
53
72
 
54
73
  ## Project Structure
@@ -75,6 +94,12 @@ For local development:
75
94
  pip install .
76
95
  ```
77
96
 
97
+ For editable local development:
98
+
99
+ ```bash
100
+ pip install -e .
101
+ ```
102
+
78
103
  After publishing to PyPI:
79
104
 
80
105
  ```bash
@@ -87,34 +112,47 @@ pip install devlinker
87
112
  devlinker
88
113
  ```
89
114
 
90
- 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):
91
122
 
92
123
  ```text
93
- Dev Linker v1.2.2
94
-
95
- [INFO] Mode: Auto (FastAPI async proxy + Docker detection)
96
- [INFO] Booting local services...
97
- [INFO] Detecting frontend/backend ports...
98
- [OK] Frontend -> 5173
99
- [OK] Backend -> 5000
100
-
101
- [OK] Proxy ready at http://localhost:8000
102
-
103
- [OK] Tunnel provider: Cloudflare
104
- [OK] Public URL:
105
- https://xxxx.trycloudflare.com
106
- Tip: Press Ctrl+Click to open link
107
-
108
- [INFO] Share this link with collaborators.
109
-
110
- DevLinker Ready (in 2.4s)
111
- Frontend: http://localhost:5173
112
- Backend: http://localhost:5000
113
- Access Links:
114
- Local: http://localhost:8000
115
- WLAN: http://192.168.1.5:8000
116
- Public: https://xxxx.trycloudflare.com
117
- Tip: Press Ctrl+Click to open link
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:
149
+
150
+ ```text
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
118
156
  ```
119
157
 
120
158
  Version check:
@@ -147,15 +185,6 @@ devlinker --docker
147
185
  By default, DevLinker starts **fast local proxy only** (no tunnel). To enable a public tunnel, use the `--url` flag:
148
186
 
149
187
 
150
- ```bash
151
- devlinker --url
152
- ```
153
-
154
- In your terminal output, you'll see:
155
-
156
-
157
- URL, run:
158
-
159
188
  ```bash
160
189
  devlinker --url
161
190
  ```
@@ -164,11 +193,11 @@ This will start the proxy and open a public tunnel (Cloudflare or ngrok). The ou
164
193
 
165
194
  ```text
166
195
  🌍 Enabling public tunnel...
167
- [OK] Tunnel provider: Cloudflare
168
- [OK] Public URL:
196
+ Tunnel provider: Cloudflare
197
+ Public URL:
169
198
  https://xxxx.trycloudflare.com
170
- Tip: Press Ctrl+Click to open link
171
- [INFO] Share this link with collaborators.
199
+ Tip: Ctrl+Click to open link
200
+ Share this link with collaborators.
172
201
  ```
173
202
 
174
203
  To force tunnel off (even if --url is passed):
@@ -228,13 +257,11 @@ devlinker --frontend 5173 --backend 5000 --proxy-port 18000
228
257
  Default behavior also tries fallback ports automatically when 8000 is busy:
229
258
 
230
259
  ```text
231
- [WARN] Port 8000 in use
232
- [INFO] Using proxy port: 8001
260
+ Port 8000 in use
261
+ Using proxy port: 8001
233
262
  ```
234
263
 
235
- - 8001
236
- - 8002
237
- - 18000
264
+ By default it scans the next 10 ports after the requested one, then tries `18000`.
238
265
 
239
266
  Frontend detection behavior:
240
267
 
@@ -253,6 +280,41 @@ fetch("/api/endpoint")
253
280
 
254
281
  Do not hardcode backend host URLs in frontend code.
255
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
+
256
318
  ## Backend Auto-Detection
257
319
 
258
320
  Backend port detection runs in this order:
@@ -308,12 +370,15 @@ For containerized Flask backends, ensure:
308
370
 
309
371
  - runner.py expects frontend project in frontend and Python app in backend/app.py.
310
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.
311
374
  - Tunnel selection order is: cloudflared (TryCloudflare), then ngrok.
312
375
  - If cloudflared is unavailable and ngrok is not configured, Dev Linker prints one-time setup guidance.
313
376
  - You may need to set ngrok auth once on your machine using ngrok config add-authtoken <token>.
314
377
  - Dev Linker prints a public URL with `ngrok-skip-browser-warning=true` only when ngrok is used.
315
378
  - Startup output includes selected tunnel provider (`cloudflare` or `ngrok`).
316
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`.
317
382
  - Proxy listens on `0.0.0.0` and can print a WLAN URL for same-network sharing.
318
383
  - If WLAN access fails on Windows, allow the proxy port in firewall and confirm devices are on the same network.
319
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).
@@ -17,9 +21,21 @@ Dev Linker runs frontend and backend dev servers, proxies both through a single
17
21
  - 🧪 **Runtime Smoke Test:** Built-in test for end-to-end proxy validation.
18
22
  - 🛠️ **Extensible:** Modular architecture for future SaaS, dashboard, and team features.
19
23
 
24
+ ## Support DevLinker
25
+
26
+ If DevLinker helps you ship faster, consider supporting the project:
27
+
28
+ > 💖 Support DevLinker
29
+ > [![UPI](https://img.shields.io/badge/UPI-devlinker%40upi-22c55e?style=for-the-badge)](upi://pay?pa=devlinker@upi&pn=DevLinker&cu=INR&tn=Support%20DevLinker%20Project%20🚀)
30
+ > [![Donate](https://img.shields.io/badge/Support-Scan%20or%20Pay-0ea5e9?style=for-the-badge)](upi://pay?pa=devlinker@upi&pn=DevLinker&cu=INR&tn=Support%20DevLinker%20Project%20🚀)
31
+
32
+ - 💖 UPI: devlinker@upi
33
+ - 🔗 UPI link: upi://pay?pa=devlinker@upi&pn=DevLinker&cu=INR&tn=Support%20DevLinker%20Project%20🚀
34
+
20
35
  ## CLI Commands & Options
21
36
 
22
37
  - `devlinker` — Start proxy (local only, fast)
38
+ - `devlinker support` — Show UPI support QR code in terminal
23
39
  - `devlinker --url` — Start with public tunnel (Cloudflare/ngrok)
24
40
  - `devlinker share` — Enable public tunnel at runtime (no restart)
25
41
  - `devlinker unshare` — Disable public tunnel at runtime
@@ -31,6 +47,7 @@ Dev Linker runs frontend and backend dev servers, proxies both through a single
31
47
  - `devlinker --no-lan` — Hide WLAN sharing URL
32
48
  - `devlinker --interactive-backend` — Prompt to choose backend if multiple found
33
49
  - `devlinker --proxy-port 18000` — Use custom proxy port
50
+ - `devlinker --debug` — Enable debug mode (turns on live API request logger)
34
51
  - `devlinker --version` — Show version
35
52
 
36
53
  ## Project Structure
@@ -57,6 +74,12 @@ For local development:
57
74
  pip install .
58
75
  ```
59
76
 
77
+ For editable local development:
78
+
79
+ ```bash
80
+ pip install -e .
81
+ ```
82
+
60
83
  After publishing to PyPI:
61
84
 
62
85
  ```bash
@@ -69,34 +92,47 @@ pip install devlinker
69
92
  devlinker
70
93
  ```
71
94
 
72
- 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):
73
102
 
74
103
  ```text
75
- Dev Linker v1.2.2
76
-
77
- [INFO] Mode: Auto (FastAPI async proxy + Docker detection)
78
- [INFO] Booting local services...
79
- [INFO] Detecting frontend/backend ports...
80
- [OK] Frontend -> 5173
81
- [OK] Backend -> 5000
82
-
83
- [OK] Proxy ready at http://localhost:8000
84
-
85
- [OK] Tunnel provider: Cloudflare
86
- [OK] Public URL:
87
- https://xxxx.trycloudflare.com
88
- Tip: Press Ctrl+Click to open link
89
-
90
- [INFO] Share this link with collaborators.
91
-
92
- DevLinker Ready (in 2.4s)
93
- Frontend: http://localhost:5173
94
- Backend: http://localhost:5000
95
- Access Links:
96
- Local: http://localhost:8000
97
- WLAN: http://192.168.1.5:8000
98
- Public: https://xxxx.trycloudflare.com
99
- Tip: Press Ctrl+Click to open link
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:
129
+
130
+ ```text
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
100
136
  ```
101
137
 
102
138
  Version check:
@@ -129,15 +165,6 @@ devlinker --docker
129
165
  By default, DevLinker starts **fast local proxy only** (no tunnel). To enable a public tunnel, use the `--url` flag:
130
166
 
131
167
 
132
- ```bash
133
- devlinker --url
134
- ```
135
-
136
- In your terminal output, you'll see:
137
-
138
-
139
- URL, run:
140
-
141
168
  ```bash
142
169
  devlinker --url
143
170
  ```
@@ -146,11 +173,11 @@ This will start the proxy and open a public tunnel (Cloudflare or ngrok). The ou
146
173
 
147
174
  ```text
148
175
  🌍 Enabling public tunnel...
149
- [OK] Tunnel provider: Cloudflare
150
- [OK] Public URL:
176
+ Tunnel provider: Cloudflare
177
+ Public URL:
151
178
  https://xxxx.trycloudflare.com
152
- Tip: Press Ctrl+Click to open link
153
- [INFO] Share this link with collaborators.
179
+ Tip: Ctrl+Click to open link
180
+ Share this link with collaborators.
154
181
  ```
155
182
 
156
183
  To force tunnel off (even if --url is passed):
@@ -210,13 +237,11 @@ devlinker --frontend 5173 --backend 5000 --proxy-port 18000
210
237
  Default behavior also tries fallback ports automatically when 8000 is busy:
211
238
 
212
239
  ```text
213
- [WARN] Port 8000 in use
214
- [INFO] Using proxy port: 8001
240
+ Port 8000 in use
241
+ Using proxy port: 8001
215
242
  ```
216
243
 
217
- - 8001
218
- - 8002
219
- - 18000
244
+ By default it scans the next 10 ports after the requested one, then tries `18000`.
220
245
 
221
246
  Frontend detection behavior:
222
247
 
@@ -235,6 +260,41 @@ fetch("/api/endpoint")
235
260
 
236
261
  Do not hardcode backend host URLs in frontend code.
237
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
+
238
298
  ## Backend Auto-Detection
239
299
 
240
300
  Backend port detection runs in this order:
@@ -290,12 +350,15 @@ For containerized Flask backends, ensure:
290
350
 
291
351
  - runner.py expects frontend project in frontend and Python app in backend/app.py.
292
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.
293
354
  - Tunnel selection order is: cloudflared (TryCloudflare), then ngrok.
294
355
  - If cloudflared is unavailable and ngrok is not configured, Dev Linker prints one-time setup guidance.
295
356
  - You may need to set ngrok auth once on your machine using ngrok config add-authtoken <token>.
296
357
  - Dev Linker prints a public URL with `ngrok-skip-browser-warning=true` only when ngrok is used.
297
358
  - Startup output includes selected tunnel provider (`cloudflare` or `ngrok`).
298
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`.
299
362
  - Proxy listens on `0.0.0.0` and can print a WLAN URL for same-network sharing.
300
363
  - If WLAN access fails on Windows, allow the proxy port in firewall and confirm devices are on the same network.
301
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"
@@ -63,8 +63,22 @@
63
63
  font-size: 0.92rem;
64
64
  font-weight: 500;
65
65
  opacity: 0.9;
66
- pointer-events: none;
67
- user-select: none;
66
+ pointer-events: auto;
67
+ user-select: text;
68
+ }
69
+ .devlinker-powered span {
70
+ display: block;
71
+ margin-top: 4px;
72
+ color: #cbd5e1;
73
+ }
74
+ .devlinker-powered a {
75
+ color: #7dd3fc;
76
+ text-decoration: none;
77
+ font-weight: 600;
78
+ }
79
+ .devlinker-powered a:hover {
80
+ color: #bae6fd;
81
+ text-decoration: underline;
68
82
  }
69
83
  @keyframes devlinker-spin {
70
84
  to { transform: rotate(360deg); }
@@ -80,7 +94,10 @@
80
94
  <div class="devlinker-health">Frontend connected • Backend connected</div>
81
95
  </div>
82
96
  </div>
83
- <div class="devlinker-powered">Powered by DevLinker</div>
97
+ <div class="devlinker-powered">
98
+ Powered by DevLinker 🚀
99
+ <span>Support the project ❤️ <a href="upi://pay?pa=devlinker@upi&pn=DevLinker&cu=INR&tn=Support%20DevLinker%20Project%20🚀">devlinker@upi</a></span>
100
+ </div>
84
101
  <script>
85
102
  // Fetch the real page and replace the loader with a short minimum display for smoothness.
86
103
  (async function() {
@@ -98,6 +98,33 @@
98
98
  font-weight: 500;
99
99
  opacity: 0.95;
100
100
  }
101
+ .devlinker-support {
102
+ color: #cbd5e1;
103
+ line-height: 1.45;
104
+ }
105
+ .devlinker-support a {
106
+ color: #7dd3fc;
107
+ text-decoration: none;
108
+ font-weight: 600;
109
+ }
110
+ .devlinker-support a:hover {
111
+ color: #bae6fd;
112
+ text-decoration: underline;
113
+ }
114
+ .devlinker-warning {
115
+ display: none;
116
+ margin-top: 12px;
117
+ border: 1px solid rgba(251, 191, 36, 0.45);
118
+ background: rgba(120, 53, 15, 0.26);
119
+ border-radius: 12px;
120
+ padding: 10px 12px;
121
+ color: #fde68a;
122
+ font-size: 0.9rem;
123
+ line-height: 1.4;
124
+ }
125
+ .devlinker-warning strong {
126
+ color: #fef3c7;
127
+ }
101
128
  @keyframes devlinker-spin {
102
129
  to { transform: rotate(360deg); }
103
130
  }
@@ -124,8 +151,12 @@
124
151
  <div class="devlinker-tip">Tip: Share your app instantly with one link. No CORS issues, no port confusion.</div>
125
152
  <div class="devlinker-tip">Go Pro: custom domains, faster sharing, and no branding.</div>
126
153
  <a class="devlinker-upgrade" href="https://devlinker.app" target="_blank" rel="noopener">Explore Pro at devlinker.app</a>
154
+ <div class="devlinker-support">Support the project ❤️ <a href="upi://pay?pa=devlinker@upi&pn=DevLinker&cu=INR&tn=Support%20DevLinker%20Project%20🚀">devlinker@upi</a></div>
155
+ <div class="devlinker-warning" id="devlinker-camera-warning">
156
+ <strong>Camera warning:</strong> camera and microphone are blocked on LAN HTTP URLs by browser policy. Use localhost or run <strong>devlinker --url</strong> for HTTPS sharing.
157
+ </div>
127
158
  </div>
128
- <div class="devlinker-powered">Powered by DevLinker</div>
159
+ <div class="devlinker-powered">Powered by DevLinker 🚀</div>
129
160
  </div>
130
161
  </div>
131
162
  <script>
@@ -149,6 +180,16 @@ const MIN_TIME = 800;
149
180
  const MAX_TIME = 5000;
150
181
  let hidden = false;
151
182
 
183
+ const cameraContext = window.__DEVLINKER_CAMERA_CONTEXT__ || {};
184
+ const warningElement = document.getElementById("devlinker-camera-warning");
185
+ if (warningElement) {
186
+ const isLan = cameraContext.mode === "lan";
187
+ const isSecure = Boolean(cameraContext.secure);
188
+ if (isLan && !isSecure) {
189
+ warningElement.style.display = "block";
190
+ }
191
+ }
192
+
152
193
  function hideLoader() {
153
194
  if (hidden) return;
154
195
  hidden = true;