79 lines
2.7 KiB
JavaScript
79 lines
2.7 KiB
JavaScript
import { readFile, writeFile } from "node:fs/promises";
|
||
import { fileURLToPath } from "node:url";
|
||
|
||
const collectionName = process.env.PUBLIC_TYPESENSE_COLLECTION || "class_memories";
|
||
const host = process.env.PUBLIC_TYPESENSE_HOST?.replace(/^https?:\/\//, "").replace(/\/$/, "");
|
||
const port = process.env.PUBLIC_TYPESENSE_PORT || "443";
|
||
const protocol = process.env.PUBLIC_TYPESENSE_PROTOCOL || "https";
|
||
const adminKey = process.env.TYPESENSE_ADMIN_API_KEY;
|
||
const existingSearchKey = process.env.PUBLIC_TYPESENSE_SEARCH_API_KEY;
|
||
const force = process.argv.includes("--force");
|
||
|
||
if (!host || !adminKey) {
|
||
throw new Error(
|
||
"缺少 Typesense 配置。请在 .env 或 .env.local 中设置 PUBLIC_TYPESENSE_HOST 和 TYPESENSE_ADMIN_API_KEY。"
|
||
);
|
||
}
|
||
|
||
const isPlaceholder = (value) =>
|
||
!value || /replace|example|your|请填写|只读密钥/i.test(value);
|
||
|
||
if (!isPlaceholder(existingSearchKey) && !force) {
|
||
throw new Error(
|
||
"PUBLIC_TYPESENSE_SEARCH_API_KEY 已存在。如需轮换密钥,请执行 npm run search:key -- --force。"
|
||
);
|
||
}
|
||
|
||
const origin = `${protocol}://${host}${
|
||
(protocol === "https" && port === "443") || (protocol === "http" && port === "80")
|
||
? ""
|
||
: `:${port}`
|
||
}`;
|
||
|
||
const response = await fetch(`${origin}/keys`, {
|
||
method: "POST",
|
||
headers: {
|
||
"Content-Type": "application/json",
|
||
"X-TYPESENSE-API-KEY": adminKey
|
||
},
|
||
body: JSON.stringify({
|
||
description: `Search-only key for ${collectionName}`,
|
||
actions: ["documents:search"],
|
||
collections: [collectionName]
|
||
})
|
||
});
|
||
|
||
const responseText = await response.text();
|
||
if (!response.ok) {
|
||
throw new Error(`创建只读密钥失败:${response.status} ${responseText}`);
|
||
}
|
||
|
||
const result = JSON.parse(responseText);
|
||
if (!result.value) {
|
||
throw new Error("Typesense 没有返回完整密钥,无法保存配置。请检查服务端响应。" );
|
||
}
|
||
|
||
const envLocalPath = fileURLToPath(new URL("../.env.local", import.meta.url));
|
||
let envLocal = "";
|
||
try {
|
||
envLocal = await readFile(envLocalPath, "utf8");
|
||
} catch (error) {
|
||
if (error.code !== "ENOENT") throw error;
|
||
}
|
||
|
||
const lineEnding = envLocal.includes("\r\n") ? "\r\n" : "\n";
|
||
const assignment = `PUBLIC_TYPESENSE_SEARCH_API_KEY=${JSON.stringify(result.value)}`;
|
||
|
||
if (/^PUBLIC_TYPESENSE_SEARCH_API_KEY=.*$/m.test(envLocal)) {
|
||
envLocal = envLocal.replace(/^PUBLIC_TYPESENSE_SEARCH_API_KEY=.*$/m, assignment);
|
||
} else {
|
||
const separator = envLocal.length === 0 || envLocal.endsWith("\n") ? "" : lineEnding;
|
||
envLocal = `${envLocal}${separator}${assignment}${lineEnding}`;
|
||
}
|
||
|
||
await writeFile(envLocalPath, envLocal, "utf8");
|
||
|
||
console.log(`已创建仅限 ${collectionName} 的 documents:search 密钥。`);
|
||
console.log(`密钥 ID:${result.id},已写入 .env.local。`);
|
||
console.log("现在可以执行 npm run search:sync 和 npm run build。");
|