dsh-composer-ux 0.2.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +32 -0
- package/README.md +16 -3
- package/lib/client.js +621 -151
- package/lib/client.js.map +4 -4
- package/lib/index.js +321 -6
- package/lib/index.js.map +4 -4
- package/package.json +3 -3
package/lib/index.js
CHANGED
|
@@ -807,7 +807,15 @@ var MENU_FIELDS = [
|
|
|
807
807
|
var MENU_NATIVE_FIELD = "menuNative";
|
|
808
808
|
var QUICK_PROMPTS_FIELD = "quickPrompts";
|
|
809
809
|
var OPTIMIZER_TIER_FIELD = "optimizerTier";
|
|
810
|
-
var
|
|
810
|
+
var QUICK_PROMPT_MAX = 60;
|
|
811
|
+
var QUICK_CATEGORY_MAX = 20;
|
|
812
|
+
var QUICK_CATEGORY_NAME_MAX = 40;
|
|
813
|
+
var QUICK_LABEL_MAX = 40;
|
|
814
|
+
var QUICK_TEXT_MAX = 2e5;
|
|
815
|
+
var OPTIMIZE_TEXT_MAX = 8e3;
|
|
816
|
+
var QUICK_PROMPTS_API_PATH = "/composer-ux/prompts";
|
|
817
|
+
var QUICK_BOOK_VERSION = 2;
|
|
818
|
+
var DEFAULT_CATEGORY_NAME = "\u9ED8\u8BA4";
|
|
811
819
|
var OPTIMIZE_OUTPUT_MAX = 12e3;
|
|
812
820
|
var OPTIMIZER_API_PATH = "/composer-ux/optimize";
|
|
813
821
|
var DEFAULT_OPTIMIZER_TIER = "advanced";
|
|
@@ -822,6 +830,99 @@ var DEFAULT_QUICK_PROMPTS = [
|
|
|
822
830
|
{ id: "builtin-8", label: "\u5199\u6D4B\u8BD5", prompt: "\u8BF7\u4E3A\u4E0B\u9762\u7684\u4EE3\u7801\u7F16\u5199\u5355\u5143\u6D4B\u8BD5\u3002", always: false },
|
|
823
831
|
{ id: "builtin-9", label: "\u4EE3\u7801\u5BA1\u67E5", prompt: "\u8BF7\u5BF9\u4E0B\u9762\u7684\u4EE3\u7801\u8FDB\u884C\u4EE3\u7801\u5BA1\u67E5\uFF0C\u6307\u51FA\u95EE\u9898\u5E76\u7ED9\u51FA\u6539\u8FDB\u5EFA\u8BAE\u3002", always: false }
|
|
824
832
|
];
|
|
833
|
+
function newQuickPromptId() {
|
|
834
|
+
return `qp-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`;
|
|
835
|
+
}
|
|
836
|
+
function newQuickCategoryId() {
|
|
837
|
+
return `qc-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`;
|
|
838
|
+
}
|
|
839
|
+
function defaultQuickBook() {
|
|
840
|
+
return {
|
|
841
|
+
version: QUICK_BOOK_VERSION,
|
|
842
|
+
categories: [{ id: "cat-default", name: DEFAULT_CATEGORY_NAME, prompts: DEFAULT_QUICK_PROMPTS }]
|
|
843
|
+
};
|
|
844
|
+
}
|
|
845
|
+
function asPromptRow(value) {
|
|
846
|
+
if (typeof value !== "object" || value === null) return void 0;
|
|
847
|
+
const row = value;
|
|
848
|
+
const either = (first, second) => {
|
|
849
|
+
const picked = typeof first === "string" && first !== "" ? first : second;
|
|
850
|
+
return typeof picked === "string" ? picked : "";
|
|
851
|
+
};
|
|
852
|
+
const prompt = either(row.prompt, row.text).slice(0, QUICK_TEXT_MAX).trim();
|
|
853
|
+
if (prompt === "") return void 0;
|
|
854
|
+
const label = either(row.label, row.title).slice(0, QUICK_LABEL_MAX).trim();
|
|
855
|
+
const id = typeof row.id === "string" && row.id !== "" ? row.id.slice(0, 64) : newQuickPromptId();
|
|
856
|
+
const order = typeof row.order === "number" && Number.isFinite(row.order) ? Math.max(1, Math.round(row.order)) : void 0;
|
|
857
|
+
return {
|
|
858
|
+
prompt: { id, label: label === "" ? prompt.slice(0, 12) : label, prompt, always: row.always === true || row.autoSend === true },
|
|
859
|
+
order
|
|
860
|
+
};
|
|
861
|
+
}
|
|
862
|
+
function toPromptList(values) {
|
|
863
|
+
const rows = [];
|
|
864
|
+
for (const value of values) {
|
|
865
|
+
const row = asPromptRow(value);
|
|
866
|
+
if (row !== void 0) rows.push({ ...row, index: rows.length });
|
|
867
|
+
}
|
|
868
|
+
rows.sort((a, b) => {
|
|
869
|
+
const left = a.order ?? Number.MAX_SAFE_INTEGER;
|
|
870
|
+
const right = b.order ?? Number.MAX_SAFE_INTEGER;
|
|
871
|
+
return left === right ? a.index - b.index : left - right;
|
|
872
|
+
});
|
|
873
|
+
const seen = /* @__PURE__ */ new Set();
|
|
874
|
+
const out = [];
|
|
875
|
+
for (const row of rows) {
|
|
876
|
+
if (out.length >= QUICK_PROMPT_MAX) break;
|
|
877
|
+
if (seen.has(row.prompt.id)) continue;
|
|
878
|
+
seen.add(row.prompt.id);
|
|
879
|
+
out.push(row.prompt);
|
|
880
|
+
}
|
|
881
|
+
return out;
|
|
882
|
+
}
|
|
883
|
+
function sanitizeBook(value) {
|
|
884
|
+
if (typeof value !== "object" || value === null) return void 0;
|
|
885
|
+
const source = value;
|
|
886
|
+
const flat = Array.isArray(value) ? value : Array.isArray(source.prompts) ? source.prompts : void 0;
|
|
887
|
+
if (flat !== void 0) {
|
|
888
|
+
const prompts = toPromptList(flat);
|
|
889
|
+
return {
|
|
890
|
+
version: QUICK_BOOK_VERSION,
|
|
891
|
+
categories: prompts.length === 0 ? [] : [{ id: "cat-default", name: DEFAULT_CATEGORY_NAME, prompts }]
|
|
892
|
+
};
|
|
893
|
+
}
|
|
894
|
+
if (!Array.isArray(source.categories)) return void 0;
|
|
895
|
+
const seen = /* @__PURE__ */ new Set();
|
|
896
|
+
const categories = [];
|
|
897
|
+
for (const raw of source.categories) {
|
|
898
|
+
if (categories.length >= QUICK_CATEGORY_MAX) break;
|
|
899
|
+
if (typeof raw !== "object" || raw === null) continue;
|
|
900
|
+
const row = raw;
|
|
901
|
+
const prompts = toPromptList(Array.isArray(row.prompts) ? row.prompts : []);
|
|
902
|
+
const wanted = typeof row.id === "string" && row.id !== "" ? row.id.slice(0, 64) : newQuickCategoryId();
|
|
903
|
+
const id = seen.has(wanted) ? newQuickCategoryId() : wanted;
|
|
904
|
+
seen.add(id);
|
|
905
|
+
const name2 = (typeof row.name === "string" ? row.name : "").slice(0, QUICK_CATEGORY_NAME_MAX).trim();
|
|
906
|
+
categories.push({ id, name: name2 === "" ? DEFAULT_CATEGORY_NAME : name2, prompts });
|
|
907
|
+
}
|
|
908
|
+
return { version: QUICK_BOOK_VERSION, categories };
|
|
909
|
+
}
|
|
910
|
+
function bookToFile(book) {
|
|
911
|
+
return {
|
|
912
|
+
version: QUICK_BOOK_VERSION,
|
|
913
|
+
categories: book.categories.map((category) => ({
|
|
914
|
+
id: category.id,
|
|
915
|
+
name: category.name,
|
|
916
|
+
prompts: category.prompts.map((prompt, index) => ({
|
|
917
|
+
id: prompt.id,
|
|
918
|
+
title: prompt.label,
|
|
919
|
+
text: prompt.prompt,
|
|
920
|
+
autoSend: prompt.always,
|
|
921
|
+
order: index + 1
|
|
922
|
+
}))
|
|
923
|
+
}))
|
|
924
|
+
};
|
|
925
|
+
}
|
|
825
926
|
var HEADER_ENABLED_FIELD = "headerEnabled";
|
|
826
927
|
var HEADER_NAME_FIELD = "headerName";
|
|
827
928
|
var HEADER_VALUE_FIELD = "headerValue";
|
|
@@ -967,6 +1068,141 @@ function buildOptimizeUser(original) {
|
|
|
967
1068
|
].join("\n");
|
|
968
1069
|
}
|
|
969
1070
|
|
|
1071
|
+
// src/quick-store.ts
|
|
1072
|
+
import { mkdir, open, readFile, rename, unlink } from "node:fs/promises";
|
|
1073
|
+
import { homedir } from "node:os";
|
|
1074
|
+
import { dirname, join } from "node:path";
|
|
1075
|
+
var QUICK_STORE_FILE = "quick-prompts.json";
|
|
1076
|
+
var LOCK_RETRY_MS = 50;
|
|
1077
|
+
var LOCK_RETRY_MAX = 40;
|
|
1078
|
+
var LOCK_STALE_MS = 3e4;
|
|
1079
|
+
function dshHome() {
|
|
1080
|
+
const fromEnv = process.env.DSH_HOME?.trim();
|
|
1081
|
+
return fromEnv !== void 0 && fromEnv !== "" ? fromEnv : join(homedir(), ".dsh");
|
|
1082
|
+
}
|
|
1083
|
+
function quickStorePath() {
|
|
1084
|
+
return join(dshHome(), QUICK_STORE_FILE);
|
|
1085
|
+
}
|
|
1086
|
+
function errorText(error) {
|
|
1087
|
+
return error instanceof Error ? error.message : String(error);
|
|
1088
|
+
}
|
|
1089
|
+
function hasCode(error, code) {
|
|
1090
|
+
return typeof error === "object" && error !== null && error.code === code;
|
|
1091
|
+
}
|
|
1092
|
+
function delay(ms) {
|
|
1093
|
+
return new Promise((resolve2) => {
|
|
1094
|
+
setTimeout(resolve2, ms);
|
|
1095
|
+
});
|
|
1096
|
+
}
|
|
1097
|
+
async function quarantine(file) {
|
|
1098
|
+
const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
1099
|
+
const target = `${file}.bad-${stamp}`;
|
|
1100
|
+
try {
|
|
1101
|
+
await rename(file, target);
|
|
1102
|
+
return target;
|
|
1103
|
+
} catch {
|
|
1104
|
+
return void 0;
|
|
1105
|
+
}
|
|
1106
|
+
}
|
|
1107
|
+
async function readQuickBook(file = quickStorePath()) {
|
|
1108
|
+
let raw;
|
|
1109
|
+
try {
|
|
1110
|
+
raw = await readFile(file, "utf8");
|
|
1111
|
+
} catch (error) {
|
|
1112
|
+
if (hasCode(error, "ENOENT")) return { kind: "missing" };
|
|
1113
|
+
return { kind: "broken", error: `\u8BFB\u53D6\u5931\u8D25\uFF1A${errorText(error)}` };
|
|
1114
|
+
}
|
|
1115
|
+
if (raw.trim() === "") return { kind: "broken", error: "\u6587\u4EF6\u662F\u7A7A\u7684", quarantined: await quarantine(file) };
|
|
1116
|
+
let parsed;
|
|
1117
|
+
try {
|
|
1118
|
+
parsed = JSON.parse(raw);
|
|
1119
|
+
} catch (error) {
|
|
1120
|
+
return { kind: "broken", error: `\u4E0D\u662F\u5408\u6CD5 JSON\uFF1A${errorText(error)}`, quarantined: await quarantine(file) };
|
|
1121
|
+
}
|
|
1122
|
+
const book = sanitizeBook(parsed);
|
|
1123
|
+
if (book === void 0) {
|
|
1124
|
+
return {
|
|
1125
|
+
kind: "broken",
|
|
1126
|
+
error: "\u7ED3\u6784\u8BA4\u4E0D\u51FA\uFF08\u65E2\u4E0D\u662F categories \u4E5F\u4E0D\u662F\u5E73\u94FA prompts\uFF09",
|
|
1127
|
+
quarantined: await quarantine(file)
|
|
1128
|
+
};
|
|
1129
|
+
}
|
|
1130
|
+
return { kind: "ok", book };
|
|
1131
|
+
}
|
|
1132
|
+
async function acquireLock(file) {
|
|
1133
|
+
const lock = `${file}.lock`;
|
|
1134
|
+
for (let attempt = 0; attempt < LOCK_RETRY_MAX; attempt += 1) {
|
|
1135
|
+
try {
|
|
1136
|
+
const handle = await open(lock, "wx", 384);
|
|
1137
|
+
await handle.close();
|
|
1138
|
+
return async () => {
|
|
1139
|
+
try {
|
|
1140
|
+
await unlink(lock);
|
|
1141
|
+
} catch {
|
|
1142
|
+
}
|
|
1143
|
+
};
|
|
1144
|
+
} catch (error) {
|
|
1145
|
+
if (!hasCode(error, "EEXIST")) throw error;
|
|
1146
|
+
let ageMs;
|
|
1147
|
+
try {
|
|
1148
|
+
const info = await open(lock, "r");
|
|
1149
|
+
try {
|
|
1150
|
+
const stat = await info.stat();
|
|
1151
|
+
ageMs = Date.now() - stat.mtimeMs;
|
|
1152
|
+
} finally {
|
|
1153
|
+
await info.close();
|
|
1154
|
+
}
|
|
1155
|
+
} catch {
|
|
1156
|
+
}
|
|
1157
|
+
if (ageMs !== void 0 && ageMs > LOCK_STALE_MS) {
|
|
1158
|
+
throw new Error(
|
|
1159
|
+
`\u5199\u5165\u9501 ${lock} \u5DF2\u5B58\u5728 ${Math.round(ageMs / 1e3)} \u79D2\uFF0C\u50CF\u662F\u4E0A\u6B21\u5199\u5165\u5D29\u6E83\u7559\u4E0B\u7684\uFF1B\u786E\u8BA4\u6CA1\u6709\u6B63\u5728\u8FD0\u884C\u7684 DSH \u540E\u5220\u9664\u5B83\u518D\u91CD\u8BD5`
|
|
1160
|
+
);
|
|
1161
|
+
}
|
|
1162
|
+
await delay(LOCK_RETRY_MS);
|
|
1163
|
+
}
|
|
1164
|
+
}
|
|
1165
|
+
throw new Error(`\u53E6\u4E00\u4E2A\u8FDB\u7A0B\u6B63\u5728\u5199\u5165 ${file}\uFF08\u7B49\u5F85 ${String(LOCK_RETRY_MS * LOCK_RETRY_MAX / 1e3)} \u79D2\u4ECD\u672A\u62FF\u5230\u9501\uFF09`);
|
|
1166
|
+
}
|
|
1167
|
+
async function writeQuickBook(book, file = quickStorePath()) {
|
|
1168
|
+
await mkdir(dirname(file), { recursive: true });
|
|
1169
|
+
const release = await acquireLock(file);
|
|
1170
|
+
try {
|
|
1171
|
+
await writeLocked(book, file);
|
|
1172
|
+
} finally {
|
|
1173
|
+
await release();
|
|
1174
|
+
}
|
|
1175
|
+
}
|
|
1176
|
+
async function writeLocked(book, file) {
|
|
1177
|
+
const safe = sanitizeBook(book) ?? { version: QUICK_BOOK_VERSION, categories: [] };
|
|
1178
|
+
const tmp = `${file}.${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}.tmp`;
|
|
1179
|
+
const handle = await open(tmp, "w", 384);
|
|
1180
|
+
try {
|
|
1181
|
+
await handle.writeFile(`${JSON.stringify(bookToFile(safe), null, 2)}
|
|
1182
|
+
`, "utf8");
|
|
1183
|
+
await handle.sync();
|
|
1184
|
+
} finally {
|
|
1185
|
+
await handle.close();
|
|
1186
|
+
}
|
|
1187
|
+
await rename(tmp, file);
|
|
1188
|
+
}
|
|
1189
|
+
async function ensureQuickBook(seed, file = quickStorePath()) {
|
|
1190
|
+
const current = await readQuickBook(file);
|
|
1191
|
+
if (current.kind !== "missing") return current;
|
|
1192
|
+
await mkdir(dirname(file), { recursive: true });
|
|
1193
|
+
const release = await acquireLock(file);
|
|
1194
|
+
try {
|
|
1195
|
+
const again = await readQuickBook(file);
|
|
1196
|
+
if (again.kind !== "missing") return again;
|
|
1197
|
+
const migrated = seed === void 0 ? void 0 : sanitizeBook({ prompts: seed });
|
|
1198
|
+
const book = migrated !== void 0 && migrated.categories.length > 0 ? migrated : defaultQuickBook();
|
|
1199
|
+
await writeLocked(book, file);
|
|
1200
|
+
return { kind: "ok", book };
|
|
1201
|
+
} finally {
|
|
1202
|
+
await release();
|
|
1203
|
+
}
|
|
1204
|
+
}
|
|
1205
|
+
|
|
970
1206
|
// src/host.ts
|
|
971
1207
|
var name = "composer-ux";
|
|
972
1208
|
var PANEL_MIN = 560;
|
|
@@ -1013,7 +1249,7 @@ function pickRoutes(providers, listed) {
|
|
|
1013
1249
|
}
|
|
1014
1250
|
return listed.filter((key) => Object.prototype.hasOwnProperty.call(providers, key));
|
|
1015
1251
|
}
|
|
1016
|
-
function
|
|
1252
|
+
function errorText2(error) {
|
|
1017
1253
|
if (error instanceof Error && error.message !== "") return error.message;
|
|
1018
1254
|
return String(error);
|
|
1019
1255
|
}
|
|
@@ -1078,7 +1314,7 @@ async function mirrorHeader(settings) {
|
|
|
1078
1314
|
await settings.mutate(LLM_NAMESPACE, providerOps);
|
|
1079
1315
|
} catch (error) {
|
|
1080
1316
|
failed = true;
|
|
1081
|
-
status = `\u5199\u5165\u5931\u8D25\uFF1A${
|
|
1317
|
+
status = `\u5199\u5165\u5931\u8D25\uFF1A${errorText2(error)}`;
|
|
1082
1318
|
}
|
|
1083
1319
|
}
|
|
1084
1320
|
const nextAppliedName = !failed && applied.length > 0 ? name2 : "";
|
|
@@ -1160,7 +1396,7 @@ function apply(ctx) {
|
|
|
1160
1396
|
ctx.inject(["webServer", "llm"], (optCtx) => {
|
|
1161
1397
|
const LLM_TIMEOUT_MS = 18e4;
|
|
1162
1398
|
const BODY_MAX_BYTES = 1e6;
|
|
1163
|
-
const TEXT_MAX =
|
|
1399
|
+
const TEXT_MAX = OPTIMIZE_TEXT_MAX;
|
|
1164
1400
|
const sendJson = (res, code, payload) => {
|
|
1165
1401
|
res.writeHead(code, { "content-type": "application/json; charset=utf-8" });
|
|
1166
1402
|
res.end(JSON.stringify(payload));
|
|
@@ -1197,7 +1433,7 @@ function apply(ctx) {
|
|
|
1197
1433
|
try {
|
|
1198
1434
|
payload = objectOf(JSON.parse(await readBody(req))) ?? {};
|
|
1199
1435
|
} catch (error) {
|
|
1200
|
-
sendJson(res, 400, { ok: false, error: `\u8BF7\u6C42\u4F53\u4E0D\u662F\u5408\u6CD5 JSON\uFF1A${
|
|
1436
|
+
sendJson(res, 400, { ok: false, error: `\u8BF7\u6C42\u4F53\u4E0D\u662F\u5408\u6CD5 JSON\uFF1A${errorText2(error)}` });
|
|
1201
1437
|
return;
|
|
1202
1438
|
}
|
|
1203
1439
|
const text = textOf(payload.text).trim();
|
|
@@ -1248,7 +1484,7 @@ function apply(ctx) {
|
|
|
1248
1484
|
}
|
|
1249
1485
|
}
|
|
1250
1486
|
} catch (error) {
|
|
1251
|
-
failure =
|
|
1487
|
+
failure = errorText2(error);
|
|
1252
1488
|
} finally {
|
|
1253
1489
|
clearTimeout(timer);
|
|
1254
1490
|
}
|
|
@@ -1274,6 +1510,85 @@ function apply(ctx) {
|
|
|
1274
1510
|
handler: handle
|
|
1275
1511
|
}), "composer-ux: prompt optimizer route");
|
|
1276
1512
|
});
|
|
1513
|
+
ctx.inject(["webServer"], (storeCtx) => {
|
|
1514
|
+
const BODY_MAX_BYTES = 8e6;
|
|
1515
|
+
const sendJson = (res, code, payload) => {
|
|
1516
|
+
res.writeHead(code, { "content-type": "application/json; charset=utf-8" });
|
|
1517
|
+
res.end(JSON.stringify(payload));
|
|
1518
|
+
};
|
|
1519
|
+
const readBody = async (req) => {
|
|
1520
|
+
const chunks = [];
|
|
1521
|
+
let total = 0;
|
|
1522
|
+
for await (const chunk of req) {
|
|
1523
|
+
const buf = Buffer.isBuffer(chunk) ? chunk : Buffer.from(String(chunk));
|
|
1524
|
+
total += buf.length;
|
|
1525
|
+
if (total > BODY_MAX_BYTES) throw new Error("\u8BF7\u6C42\u4F53\u8FC7\u5927");
|
|
1526
|
+
chunks.push(buf);
|
|
1527
|
+
}
|
|
1528
|
+
return Buffer.concat(chunks).toString("utf8");
|
|
1529
|
+
};
|
|
1530
|
+
const legacyPrompts = () => {
|
|
1531
|
+
try {
|
|
1532
|
+
const settings = storeCtx.get("settings");
|
|
1533
|
+
const row = objectOf(settings?.get(NAMESPACE));
|
|
1534
|
+
const list = row?.[QUICK_PROMPTS_FIELD];
|
|
1535
|
+
return Array.isArray(list) ? list : void 0;
|
|
1536
|
+
} catch {
|
|
1537
|
+
return void 0;
|
|
1538
|
+
}
|
|
1539
|
+
};
|
|
1540
|
+
const handle = async (req, res) => {
|
|
1541
|
+
const method = (req.method ?? "GET").toUpperCase();
|
|
1542
|
+
if (method !== "GET" && method !== "POST") {
|
|
1543
|
+
sendJson(res, 405, { ok: false, error: "\u53EA\u63A5\u53D7 GET / POST" });
|
|
1544
|
+
return;
|
|
1545
|
+
}
|
|
1546
|
+
const file = quickStorePath();
|
|
1547
|
+
const outcome = await ensureQuickBook(legacyPrompts(), file);
|
|
1548
|
+
if (outcome.kind === "broken") {
|
|
1549
|
+
sendJson(res, 200, {
|
|
1550
|
+
ok: false,
|
|
1551
|
+
file,
|
|
1552
|
+
error: `\u5FEB\u6377\u6307\u4EE4\u6587\u4EF6\u8BFB\u4E0D\u4E86\uFF1A${outcome.error}`,
|
|
1553
|
+
quarantined: outcome.quarantined ?? ""
|
|
1554
|
+
});
|
|
1555
|
+
return;
|
|
1556
|
+
}
|
|
1557
|
+
if (method === "GET") {
|
|
1558
|
+
sendJson(res, 200, { ok: true, file, book: outcome.book });
|
|
1559
|
+
return;
|
|
1560
|
+
}
|
|
1561
|
+
let payload;
|
|
1562
|
+
try {
|
|
1563
|
+
payload = objectOf(JSON.parse(await readBody(req))) ?? {};
|
|
1564
|
+
} catch (error) {
|
|
1565
|
+
sendJson(res, 400, { ok: false, error: `\u8BF7\u6C42\u4F53\u4E0D\u662F\u5408\u6CD5 JSON\uFF1A${errorText2(error)}` });
|
|
1566
|
+
return;
|
|
1567
|
+
}
|
|
1568
|
+
const candidate = payload.book !== void 0 ? payload.book : payload;
|
|
1569
|
+
const next = sanitizeBook(candidate);
|
|
1570
|
+
if (next === void 0) {
|
|
1571
|
+
sendJson(res, 400, {
|
|
1572
|
+
ok: false,
|
|
1573
|
+
error: "\u63D0\u4EA4\u7684\u7ED3\u6784\u8BA4\u4E0D\u51FA\uFF08\u671F\u671B { book: { categories: [...] } } \u6216 { categories: [...] }\uFF09"
|
|
1574
|
+
});
|
|
1575
|
+
return;
|
|
1576
|
+
}
|
|
1577
|
+
try {
|
|
1578
|
+
await writeQuickBook(next, file);
|
|
1579
|
+
} catch (error) {
|
|
1580
|
+
sendJson(res, 500, { ok: false, error: `\u5199\u5165\u5931\u8D25\uFF1A${errorText2(error)}` });
|
|
1581
|
+
return;
|
|
1582
|
+
}
|
|
1583
|
+
const verified = await readQuickBook(file);
|
|
1584
|
+
sendJson(res, 200, { ok: true, file, book: verified.kind === "ok" ? verified.book : next });
|
|
1585
|
+
};
|
|
1586
|
+
storeCtx.effect(() => storeCtx.webServer.register({
|
|
1587
|
+
kind: "exact",
|
|
1588
|
+
path: QUICK_PROMPTS_API_PATH,
|
|
1589
|
+
handler: handle
|
|
1590
|
+
}), "composer-ux: quick prompt store route");
|
|
1591
|
+
});
|
|
1277
1592
|
}
|
|
1278
1593
|
export {
|
|
1279
1594
|
apply,
|