v0.1.6 — fix hit tracking: default 302, no-cache headers, 301-warning in UI

This commit is contained in:
Hendrik 2026-05-01 18:53:46 +02:00
parent 8fe9f13c56
commit d695d4c8c9
6 changed files with 26 additions and 9 deletions

View file

@ -59,7 +59,10 @@ export default async function DomainDetailPage({ params }: { params: Promise<{ i
) : "—"}
</Row>
{group && <Row k="Gruppe"><Badge variant="blue">{group.name}</Badge></Row>}
<Row k="Code">{domain.redirect_code}</Row>
<Row k="Code">
{domain.redirect_code}
{domain.redirect_code === 301 && <span className="ml-1 text-[10px] text-amber-400" title="301 wird vom Browser gecacht"></span>}
</Row>
<Row k="Pfad übernehmen">{domain.preserve_path ? "ja" : "nein"}</Row>
<Row k="www-Subdomain">{domain.include_www ? "ja" : "nein"}</Row>
<Row k="Verifiziert">{domain.verified_at ? new Date(domain.verified_at).toLocaleString("de-DE") : "—"}</Row>

View file

@ -31,7 +31,7 @@ export default function NewDomainPage() {
const [targetMode, setTargetMode] = useState<"url" | "group">("url");
const [targetUrl, setTargetUrl] = useState("");
const [groupId, setGroupId] = useState<number | "">("");
const [redirectCode, setRedirectCode] = useState<301 | 302>(301);
const [redirectCode, setRedirectCode] = useState<301 | 302>(302);
const [preservePath, setPreservePath] = useState(true);
const [includeWww, setIncludeWww] = useState(true);
const [groups, setGroups] = useState<Group[]>([]);
@ -152,9 +152,14 @@ export default function NewDomainPage() {
onChange={(e) => setRedirectCode(Number(e.target.value) as 301 | 302)}
className="flex h-9 w-full rounded-md border border-input bg-zinc-950 px-3 py-1 text-sm text-zinc-100"
>
<option value={302} className="bg-zinc-900 text-zinc-100">302 Temporär (empfohlen)</option>
<option value={301} className="bg-zinc-900 text-zinc-100">301 Permanent</option>
<option value={302} className="bg-zinc-900 text-zinc-100">302 Temporär</option>
</select>
{redirectCode === 301 && (
<p className="text-[11px] text-amber-400">
301 wird vom Browser gecacht Folge-Aufrufe gehen direkt zum Ziel ohne hier gezählt zu werden.
</p>
)}
</div>
<div className="flex items-end gap-4">
<label className="flex items-center gap-2 text-sm">

View file

@ -17,7 +17,7 @@ export default function GroupsPage() {
const [open, setOpen] = useState(false);
const [name, setName] = useState("");
const [targetUrl, setTargetUrl] = useState("");
const [code, setCode] = useState<301 | 302>(301);
const [code, setCode] = useState<301 | 302>(302);
const [creating, setCreating] = useState(false);
const [error, setError] = useState("");
@ -90,9 +90,12 @@ export default function GroupsPage() {
<div className="space-y-2">
<Label htmlFor="code">Status-Code</Label>
<select id="code" value={code} onChange={(e) => setCode(Number(e.target.value) as 301 | 302)} className="flex h-9 w-full rounded-md border border-input bg-zinc-950 px-3 py-1 text-sm text-zinc-100">
<option value={302} className="bg-zinc-900 text-zinc-100">302 Temporär (empfohlen)</option>
<option value={301} className="bg-zinc-900 text-zinc-100">301 Permanent</option>
<option value={302} className="bg-zinc-900 text-zinc-100">302 Temporär</option>
</select>
{code === 301 && (
<p className="text-[11px] text-amber-400"> 301 wird vom Browser gecacht Hits gehen verloren.</p>
)}
</div>
{error && <p className="text-sm text-destructive">{error}</p>}
<div className="flex justify-end">

View file

@ -33,7 +33,7 @@ function ensureSchema(db: Database.Database) {
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
target_url TEXT NOT NULL,
redirect_code INTEGER NOT NULL DEFAULT 301,
redirect_code INTEGER NOT NULL DEFAULT 302,
created_by INTEGER REFERENCES users(id),
created_at INTEGER NOT NULL
);
@ -44,7 +44,7 @@ function ensureSchema(db: Database.Database) {
status TEXT NOT NULL DEFAULT 'pending',
target_url TEXT,
group_id INTEGER REFERENCES domain_groups(id) ON DELETE SET NULL,
redirect_code INTEGER NOT NULL DEFAULT 301,
redirect_code INTEGER NOT NULL DEFAULT 302,
preserve_path INTEGER NOT NULL DEFAULT 1,
include_www INTEGER NOT NULL DEFAULT 1,
created_by INTEGER REFERENCES users(id),

View file

@ -1,6 +1,6 @@
{
"name": "corex-nexredirect",
"version": "0.1.5",
"version": "0.1.6",
"license": "MIT",
"scripts": {
"dev": "tsx watch server.ts",

View file

@ -41,7 +41,13 @@ app.prepare().then(() => {
const target = resolved.preserve_path
? resolved.target_url + (parsedUrl.path || "")
: resolved.target_url;
res.writeHead(resolved.redirect_code || 301, { Location: target });
res.writeHead(resolved.redirect_code || 302, {
Location: target,
// Forbid caching so every hit reaches us for analytics.
"Cache-Control": "no-store, no-cache, must-revalidate, max-age=0",
Pragma: "no-cache",
Expires: "0",
});
res.end();
return;
}