t159 重打包(Arcrun@062757f):補 /portal/daemon/libraries 登記端點(portal 庫目錄空的根因)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-31 14:07:40 +08:00
parent 216d3512c6
commit 85645941a6
2 changed files with 70 additions and 2 deletions
+2 -2
View File
@@ -1,7 +1,7 @@
{
"schema": "arcrun-rag-bundles/v1",
"built": "2026-07-31",
"source": "Arcrun@7e631a8",
"source": "Arcrun@062757f",
"core": [
{
"name": "arcrun-array-ops",
@@ -503,7 +503,7 @@
"tier": 2,
"main_file": "tier2/cypher/index.js",
"main_module": "index.js",
"sha256": "68f723dfe927c8a3dc016189c9f87188f806a443ae96d0632badb2b8541f970d",
"sha256": "73c50e8bc75f13f6f0adcf39d08892d78ceb0ccc34067d3c6533a09c3138b1e0",
"compat_date": "2025-02-19",
"compat_flags": [
"nodejs_compat",
+68
View File
@@ -11628,6 +11628,22 @@ webhooksNamedRouter.post("/webhooks/named/:ns/:name/query", async (c) => {
webhooksNamedRouter.get("/q/:ns/:name", async (c) => {
return queryNamed(c, c.req.param("ns"), c.req.param("name"), queryStringContext(c));
});
webhooksNamedRouter.get("/webhooks/named/:name/definition", async (c) => {
const apiKey = c.req.header("X-Arcrun-API-Key");
if (!apiKey) return c.json({ error: "\u7F3A\u5C11 X-Arcrun-API-Key header" }, 401);
const name = c.req.param("name");
const raw2 = await c.env.WEBHOOKS.get(kvKey(apiKey, name), "text");
if (!raw2) return c.json({ error: `\u627E\u4E0D\u5230 workflow "${name}"` }, 404);
const rec = JSON.parse(raw2);
return c.json({
name: rec.name,
description: rec.description ?? "",
graph: rec.graph,
config: rec.config ?? {},
created_at: rec.created_at ?? "",
...rec.cron_expr ? { cron_expr: rec.cron_expr } : {}
});
});
webhooksNamedRouter.get("/webhooks/named", async (c) => {
const apiKey = c.req.header("X-Arcrun-API-Key");
if (!apiKey) {
@@ -14024,6 +14040,58 @@ portalRouter.post(
return c.json({ success: true, library: created.record ? toPublicLibrary(created.record) : { name } });
})
);
portalRouter.post(
"/portal/daemon/libraries",
(c) => run(c, async () => {
const body = await c.req.json().catch(() => null);
const email = String(body?.email ?? "").trim().toLowerCase();
const password = String(body?.password ?? "");
if (!email || !password) return c.json({ error: "email \u8207 password \u5FC5\u586B" }, 400);
const items = Array.isArray(body?.libraries) ? body.libraries : [];
if (items.length === 0) return c.json({ success: true, registered: [], skipped: [] });
if (await isLocked(c.env, email)) return c.json({ error: "\u767B\u5165\u5931\u6557\u6B21\u6578\u904E\u591A\uFF0C\u8ACB\u7A0D\u5F8C\u518D\u8A66" }, 429);
const recordId = await findUserRecordId(c.env, email);
const rec = recordId ? await getRecordById(c.env, recordId) : null;
if (!rec || (rec.values.status ?? "") !== "active" || !await verifyPassword(password, rec.values.password_hash ?? "")) {
await recordLoginFail(c.env, email);
return c.json({ error: "email \u6216\u5BC6\u78BC\u932F\u8AA4" }, 401);
}
await clearLoginFail(c.env, email);
const seeded = await ensurePortalTemplates(c.env);
if (seeded.errors.length > 0) {
return c.json({ error: `portal templates seed \u5931\u6557\uFF1A${seeded.errors.join("; ")}` }, 502);
}
const existing = await listRecordsByTemplate(c.env, LIBRARY_TEMPLATE);
const have = new Set(existing.map((l) => l.values.name ?? ""));
const ns = portalNamespace(c.env);
const registered = [];
const skipped = [];
for (const it of items) {
const name = String(it?.name ?? "").trim();
const displayName = String(it?.display_name ?? "").trim() || name;
if (!isValidLibraryName(name) || name === "*") {
skipped.push(name || "(\u7A7A)");
continue;
}
if (have.has(name)) {
skipped.push(name);
continue;
}
const res = await kbdbFetch(c.env, "/records", {
method: "POST",
body: JSON.stringify({
template: LIBRARY_TEMPLATE,
owner_id: ns,
values: { name, display_name: displayName, description: "", status: "active" }
})
});
if (!res.ok) throw new KbdbError(`POST /records\uFF08portal_library\uFF0Cdaemon \u767B\u8A18\uFF09\u2192 ${res.status}`);
have.add(name);
registered.push(name);
}
return c.json({ success: true, registered, skipped });
})
);
portalRouter.patch(
"/portal/admin/libraries/:id",
(c) => run(c, async () => {