fix: support LAN access in local dev with wildcard host matching

- PUBLIC_HOST/PRIVATE_HOST='*' matches any hostname (localhost, LAN IPs)
- Public route falls through to private on 404 (shared host in local dev)
- If both return 404, keep original public 404 response
- APP_BASE_URL updated to http://localhost:8787 for local dev
This commit is contained in:
Hermes Agent
2026-06-20 15:42:21 +10:00
parent 1b723282f2
commit aac1decc71
5 changed files with 33 additions and 27 deletions
+11 -22
View File
@@ -146,7 +146,8 @@
"resolved": "https://registry.npmjs.org/@cloudflare/workers-types/-/workers-types-4.20260619.1.tgz",
"integrity": "sha512-bprsNzG0DapQPFwU2AvQlQ6FUO7Y4bKWaPBzLNI7nBSqlHsK0P62xx2NaNT6i/htzAgQspKZm1D32y0RxofrRQ==",
"dev": true,
"license": "MIT OR Apache-2.0"
"license": "MIT OR Apache-2.0",
"peer": true
},
"node_modules/@cspotcode/source-map-support": {
"version": "0.8.1",
@@ -161,27 +162,6 @@
"node": ">=12"
}
},
"node_modules/@emnapi/core": {
"version": "1.11.1",
"resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.11.1.tgz",
"integrity": "sha512-RSvbQmHzdKzNsLYa/wHrbc3KN4sYLKAdPZxqiM2HATqv/SBk2/ENSHpvXGaLOMcsAyz0poEGqkmmKYG3OWiJEQ==",
"license": "MIT",
"optional": true,
"dependencies": {
"@emnapi/wasi-threads": "1.2.2",
"tslib": "^2.4.0"
}
},
"node_modules/@emnapi/runtime": {
"version": "1.11.1",
"resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.11.1.tgz",
"integrity": "sha512-vgj7R3y3Wgx24IQaGPA/R6YFXLHVMOZ0uVEyIQPaWs+rd1AzfEMXlAC22FYwO1XkKR6NPsq7mUandH8oIRdZFw==",
"license": "MIT",
"optional": true,
"dependencies": {
"tslib": "^2.4.0"
}
},
"node_modules/@emnapi/wasi-threads": {
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.2.tgz",
@@ -3381,6 +3361,7 @@
"integrity": "sha512-MXfmqaVPEVgkBT/aY0aGCkRWWtByiYQXo3xdQ8r5RzuFrPiRn8Gar2tQdXSUQ2GKV3bkXckek89V8wQBY2Q/Aw==",
"devOptional": true,
"license": "MIT",
"peer": true,
"dependencies": {
"csstype": "^3.2.2"
}
@@ -3391,6 +3372,7 @@
"integrity": "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==",
"devOptional": true,
"license": "MIT",
"peer": true,
"peerDependencies": {
"@types/react": "^19.2.0"
}
@@ -3674,6 +3656,7 @@
"devOptional": true,
"hasInstallScript": true,
"license": "MIT",
"peer": true,
"bin": {
"esbuild": "bin/esbuild"
},
@@ -4139,6 +4122,7 @@
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz",
"integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==",
"license": "MIT",
"peer": true,
"engines": {
"node": ">=12"
},
@@ -4256,6 +4240,7 @@
"resolved": "https://registry.npmjs.org/react/-/react-19.2.7.tgz",
"integrity": "sha512-HNe9WslTbXmFK8o8cmwgAeJFSBvt1bPdHCVKtaaV+WlAN36mpT4hcRpwbf3fY56ar2oIXzsBpOAiIRHAdY0OlQ==",
"license": "MIT",
"peer": true,
"engines": {
"node": ">=0.10.0"
}
@@ -4265,6 +4250,7 @@
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.7.tgz",
"integrity": "sha512-t0BRVXvbiE/o20Hfw669rLbMCDWtYZLvmJigy2f0MxsXF+71pxhR3xOkspmsO8h3ZlNzyibAmtCa3l4lYKk6gQ==",
"license": "MIT",
"peer": true,
"dependencies": {
"scheduler": "^0.27.0"
},
@@ -4589,6 +4575,7 @@
"integrity": "sha512-i7qRCmY42zmCwnYlh9H2SvLEypEFGye5iRmEMKjcGi7zk9UquigRjFtTLz0TYqr0ZGLZhaMHl/foy1bZR+Cwlw==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"pathe": "^2.0.3"
}
@@ -4641,6 +4628,7 @@
"resolved": "https://registry.npmjs.org/vite/-/vite-8.0.16.tgz",
"integrity": "sha512-h9bXPmJichP5fLmVQo3PyaGSDE2n3aPuomeAlVRm0JLmt4rY6zmPKd59HYI4LNW8oTK7tlTsuC7l/m7awx9Jcw==",
"license": "MIT",
"peer": true,
"dependencies": {
"lightningcss": "^1.32.0",
"picomatch": "^4.0.4",
@@ -4827,6 +4815,7 @@
"dev": true,
"hasInstallScript": true,
"license": "Apache-2.0",
"peer": true,
"bin": {
"workerd": "bin/workerd"
},
+17 -2
View File
@@ -55,12 +55,27 @@ export default {
return withPrivateHostNoStoreHeaders(url, json({ error: 'Not found' }, { status: 404 }), env.PRIVATE_HOST);
}
// In local dev (PUBLIC_HOST=*), public and private share the same host.
// Try public first; if it returns 404 (alias not found), fall through to
// private so authenticated users can resolve their personal shortlinks.
// If private also returns 404, keep the original public 404 response.
if (isHeygoPublicHost(url.hostname, env.PUBLIC_HOST) && !isReservedPublicPath(url.pathname)) {
return handlePublicShortlink(request, env, ctx);
const publicResponse = await handlePublicShortlink(request, env, ctx);
if (publicResponse.status !== 404) {
return withPrivateHostNoStoreHeaders(url, publicResponse, env.PRIVATE_HOST);
}
// Public alias not found — try private route (for local dev with shared host)
if (isHeygoPrivateHost(url.hostname, env.PRIVATE_HOST)) {
const privateResponse = await handlePrivateShortlink(request, env, ctx);
if (privateResponse.status !== 404) {
return withPrivateHostNoStoreHeaders(url, privateResponse, env.PRIVATE_HOST);
}
}
return withPrivateHostNoStoreHeaders(url, publicResponse, env.PRIVATE_HOST);
}
if (isHeygoPrivateHost(url.hostname, env.PRIVATE_HOST) && !isReservedPublicPath(url.pathname)) {
return handlePrivateShortlink(request, env, ctx);
return withPrivateHostNoStoreHeaders(url, await handlePrivateShortlink(request, env, ctx), env.PRIVATE_HOST);
}
return withPrivateHostNoStoreHeaders(url, json({ error: 'Not found' }, { status: 404 }), env.PRIVATE_HOST);
+1
View File
@@ -31,6 +31,7 @@ LIMIT 1`;
const CLICK_COUNT_UPDATE = `UPDATE links SET click_count = click_count + 1, updated_at = strftime('%Y-%m-%dT%H:%M:%fZ', 'now') WHERE id=?`;
export function isHeygoPrivateHost(hostname: string, privateHost: string): boolean {
if (privateHost === '*') return true; // local dev: match any host (LAN access)
return hostname === privateHost;
}
+1
View File
@@ -27,6 +27,7 @@ export function isReservedPublicPath(pathname: string): boolean {
}
export function isHeygoPublicHost(hostname: string, publicHost: string): boolean {
if (publicHost === '*') return true; // local dev: match any host (LAN access)
return hostname === publicHost;
}
+3 -3
View File
@@ -11,9 +11,9 @@
"enabled": true
},
"vars": {
"PUBLIC_HOST": "localhost",
"PRIVATE_HOST": "localhost",
"APP_BASE_URL": "http://localhost:5173",
"PUBLIC_HOST": "*",
"PRIVATE_HOST": "*",
"APP_BASE_URL": "http://localhost:8787",
"COOKIE_DOMAIN": ""
},
"d1_databases": [