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.
- {devlinker-1.3.8/devlinker.egg-info → devlinker-1.4.1}/PKG-INFO +111 -46
- {devlinker-1.3.8 → devlinker-1.4.1}/README.md +108 -45
- devlinker-1.4.1/devlinker/config.py +17 -0
- {devlinker-1.3.8 → devlinker-1.4.1}/devlinker/detector_ai.py +6 -1
- {devlinker-1.3.8 → devlinker-1.4.1}/devlinker/devlinker_loader_instant.html +20 -3
- {devlinker-1.3.8 → devlinker-1.4.1}/devlinker/devlinker_loader_snippet.html +42 -1
- devlinker-1.4.1/devlinker/main.py +710 -0
- {devlinker-1.3.8 → devlinker-1.4.1}/devlinker/proxy.py +170 -28
- {devlinker-1.3.8 → devlinker-1.4.1}/devlinker/runner.py +77 -27
- {devlinker-1.3.8 → devlinker-1.4.1/devlinker.egg-info}/PKG-INFO +111 -46
- devlinker-1.4.1/devlinker.egg-info/entry_points.txt +2 -0
- {devlinker-1.3.8 → devlinker-1.4.1}/devlinker.egg-info/requires.txt +2 -0
- {devlinker-1.3.8 → devlinker-1.4.1}/pyproject.toml +4 -2
- devlinker-1.3.8/devlinker/config.py +0 -8
- devlinker-1.3.8/devlinker/main.py +0 -304
- devlinker-1.3.8/devlinker.egg-info/entry_points.txt +0 -2
- {devlinker-1.3.8 → devlinker-1.4.1}/LICENSE +0 -0
- {devlinker-1.3.8 → devlinker-1.4.1}/MANIFEST.in +0 -0
- {devlinker-1.3.8 → devlinker-1.4.1}/devlinker/__init__.py +0 -0
- {devlinker-1.3.8 → devlinker-1.4.1}/devlinker/detection_state.py +0 -0
- {devlinker-1.3.8 → devlinker-1.4.1}/devlinker/detector.py +0 -0
- {devlinker-1.3.8 → devlinker-1.4.1}/devlinker/doctor.py +0 -0
- {devlinker-1.3.8 → devlinker-1.4.1}/devlinker/fix.py +0 -0
- {devlinker-1.3.8 → devlinker-1.4.1}/devlinker/fixer.py +0 -0
- {devlinker-1.3.8 → devlinker-1.4.1}/devlinker/global_state.py +0 -0
- {devlinker-1.3.8 → devlinker-1.4.1}/devlinker/inspect.py +0 -0
- {devlinker-1.3.8 → devlinker-1.4.1}/devlinker/logger.py +0 -0
- {devlinker-1.3.8 → devlinker-1.4.1}/devlinker/monitor.py +0 -0
- {devlinker-1.3.8 → devlinker-1.4.1}/devlinker/share.py +0 -0
- {devlinker-1.3.8 → devlinker-1.4.1}/devlinker/tunnel.py +0 -0
- {devlinker-1.3.8 → devlinker-1.4.1}/devlinker.egg-info/SOURCES.txt +0 -0
- {devlinker-1.3.8 → devlinker-1.4.1}/devlinker.egg-info/dependency_links.txt +0 -0
- {devlinker-1.3.8 → devlinker-1.4.1}/devlinker.egg-info/top_level.txt +0 -0
- {devlinker-1.3.8 → devlinker-1.4.1}/setup.cfg +0 -0
- {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
|
+
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
|
|
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://pay?pa=devlinker@upi&pn=DevLinker&cu=INR&tn=Support%20DevLinker%20Project%20🚀)
|
|
50
|
+
> [](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
|
-
|
|
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
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
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
|
-
|
|
168
|
-
|
|
196
|
+
✔ Tunnel provider: Cloudflare
|
|
197
|
+
✔ Public URL:
|
|
169
198
|
https://xxxx.trycloudflare.com
|
|
170
|
-
Tip:
|
|
171
|
-
|
|
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
|
-
|
|
232
|
-
|
|
260
|
+
⚠ Port 8000 in use
|
|
261
|
+
ℹ Using proxy port: 8001
|
|
233
262
|
```
|
|
234
263
|
|
|
235
|
-
|
|
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
|
|
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://pay?pa=devlinker@upi&pn=DevLinker&cu=INR&tn=Support%20DevLinker%20Project%20🚀)
|
|
30
|
+
> [](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
|
-
|
|
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
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
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
|
-
|
|
150
|
-
|
|
176
|
+
✔ Tunnel provider: Cloudflare
|
|
177
|
+
✔ Public URL:
|
|
151
178
|
https://xxxx.trycloudflare.com
|
|
152
|
-
Tip:
|
|
153
|
-
|
|
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
|
-
|
|
214
|
-
|
|
240
|
+
⚠ Port 8000 in use
|
|
241
|
+
ℹ Using proxy port: 8001
|
|
215
242
|
```
|
|
216
243
|
|
|
217
|
-
|
|
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
|
|
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:
|
|
67
|
-
user-select:
|
|
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">
|
|
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
|
|
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;
|