feat: integrate todo note microservice and modularize frontend

This commit is contained in:
Codex
2026-05-05 10:33:26 +00:00
parent abd40fa252
commit 1d0046dc50
28 changed files with 2121 additions and 381 deletions
+17 -3
View File
@@ -1018,7 +1018,7 @@ function assertAllowedMicroserviceBase(rawBaseUrl: string): URL {
const baseUrl = new URL(rawBaseUrl);
if (baseUrl.protocol !== "http:") throw new Error(`microservice backend only supports http URLs, got ${baseUrl.protocol}`);
const host = baseUrl.hostname.toLowerCase();
const allowedHosts = new Set(["127.0.0.1", "localhost", "host.docker.internal"]);
const allowedHosts = new Set(["127.0.0.1", "localhost", "host.docker.internal", "todo-note"]);
if (!allowedHosts.has(host)) throw new Error(`microservice backend host is not allowed: ${baseUrl.hostname}`);
return baseUrl;
}
@@ -1060,7 +1060,9 @@ function applyJsonArrayLimits(bodyText: string, contentType: string, limits: Rec
}
async function runMicroserviceHttp(payload: Record<string, JsonValue>): Promise<JsonValue> {
const method = payload.method === "HEAD" ? "HEAD" : "GET";
const rawMethod = String(payload.method || "GET").toUpperCase();
const allowedMethods = new Set(["GET", "HEAD", "POST", "PUT", "PATCH", "DELETE"]);
const method = allowedMethods.has(rawMethod) ? rawMethod : "GET";
const targetBaseUrl = payloadString(payload, "targetBaseUrl");
if (targetBaseUrl === null) throw new Error("microservice.http requires targetBaseUrl");
const path = payloadString(payload, "path") ?? "/";
@@ -1072,10 +1074,22 @@ async function runMicroserviceHttp(payload: Record<string, JsonValue>): Promise<
url.search = query;
const timeoutMs = Math.max(1000, Math.min(30_000, payloadNumber(payload, "timeoutMs", 10_000)));
const jsonArrayLimits = payloadJsonArrayLimits(payload);
const bodyText = payloadString(payload, "bodyText") ?? "";
const requestHeaders = typeof payload.requestHeaders === "object" && payload.requestHeaders !== null && !Array.isArray(payload.requestHeaders)
? payload.requestHeaders as Record<string, JsonValue>
: {};
const headers = new Headers();
const contentType = typeof requestHeaders["content-type"] === "string" ? requestHeaders["content-type"] : "";
if (contentType.length > 0) headers.set("content-type", contentType);
const controller = new AbortController();
const timer = setTimeout(() => controller.abort(), timeoutMs);
try {
const response = await fetch(url, { method, signal: controller.signal });
const response = await fetch(url, {
method,
headers,
body: method === "GET" || method === "HEAD" ? undefined : bodyText,
signal: controller.signal,
});
const rawBodyText = await response.text();
const contentType = response.headers.get("content-type") ?? "text/plain; charset=utf-8";
const transformed = applyJsonArrayLimits(rawBodyText, contentType, jsonArrayLimits);