feat: add HTTP response and parsing helpers for form-based UX flows

This commit is contained in:
Codex
2026-02-18 12:54:05 +00:00
parent 4e443c3507
commit 8be203fb91
2 changed files with 134 additions and 0 deletions

103
src/lib/http.js Normal file
View File

@@ -0,0 +1,103 @@
"use strict";
function json(status, data, extraHeaders) {
return {
status,
headers: {
"content-type": "application/json; charset=utf-8",
...(extraHeaders || {}),
},
body: JSON.stringify(data),
};
}
function html(status, markup, extraHeaders) {
return {
status,
headers: {
"content-type": "text/html; charset=utf-8",
...(extraHeaders || {}),
},
body: markup,
};
}
function text(status, body, contentType, extraHeaders) {
return {
status,
headers: {
"content-type": contentType || "text/plain; charset=utf-8",
...(extraHeaders || {}),
},
body,
};
}
function redirect(location, extraHeaders) {
return {
status: 303,
headers: {
location,
...(extraHeaders || {}),
},
body: "",
};
}
function parseJSON(rawBody) {
if (!rawBody) {
return {};
}
try {
return JSON.parse(rawBody);
} catch {
throw new Error("invalid_json");
}
}
function parseFormUrlEncoded(rawBody) {
if (!rawBody) {
return {};
}
return String(rawBody)
.split("&")
.filter(Boolean)
.reduce((acc, part) => {
const idx = part.indexOf("=");
if (idx === -1) {
const key = decodeURIComponent(part.replaceAll("+", " "));
acc[key] = "";
return acc;
}
const key = decodeURIComponent(part.slice(0, idx).replaceAll("+", " "));
const value = decodeURIComponent(part.slice(idx + 1).replaceAll("+", " "));
acc[key] = value;
return acc;
}, {});
}
function withQuery(path, queryObj) {
const entries = Object.entries(queryObj || {}).filter(([, v]) => v !== undefined && v !== null && v !== "");
if (entries.length === 0) {
return path;
}
const query = entries
.map(([k, v]) => `${encodeURIComponent(k)}=${encodeURIComponent(String(v))}`)
.join("&");
return `${path}?${query}`;
}
module.exports = {
json,
html,
text,
redirect,
parseJSON,
parseFormUrlEncoded,
withQuery,
};