mirror of
https://github.com/better-auth/better-auth.git
synced 2026-10-18 11:32:15 -05:00
115 lines
3.0 KiB
TypeScript
115 lines
3.0 KiB
TypeScript
import "dotenv/config";
|
|
import * as fs from "node:fs";
|
|
import { Client } from "typesense";
|
|
import type { DocumentRecord } from "typesense-fumadocs-adapter";
|
|
import { getDefaultCollectionFields, sync } from "typesense-fumadocs-adapter";
|
|
|
|
const typesenseCollectionName = "better-auth-docs";
|
|
const typesenseLocale = "en";
|
|
|
|
// The adapter types tags as strings but creates a string[] field, which rejects imports.
|
|
const typesenseCollectionFields = getDefaultCollectionFields(
|
|
typesenseLocale,
|
|
).map((field): typeof field =>
|
|
field.name === "tag" ? { ...field, type: "string" } : field,
|
|
);
|
|
|
|
export function getTypesenseSyncOptions(documents: DocumentRecord[]) {
|
|
return {
|
|
typesenseCollectionName,
|
|
documents: documents.map((document) => ({
|
|
...document,
|
|
locale: typesenseLocale,
|
|
})),
|
|
customLocaleCollectionSettings: {
|
|
[typesenseLocale]: {
|
|
field_definitions: typesenseCollectionFields,
|
|
},
|
|
},
|
|
};
|
|
}
|
|
|
|
export function getTypesenseSyncSkipReason(env: NodeJS.ProcessEnv) {
|
|
const url = env.NEXT_PUBLIC_TYPESENSE_SERVER_URL;
|
|
const adminKey = env.TYPESENSE_ADMIN_API_KEY;
|
|
|
|
if (!url || !adminKey) {
|
|
return "[Typesense] env vars not set, skipping sync.";
|
|
}
|
|
|
|
if (!env.VERCEL) {
|
|
return "[Typesense] not running on Vercel, skipping sync.";
|
|
}
|
|
|
|
if (!env.VERCEL_ENV) {
|
|
return "[Typesense] Vercel environment is missing, skipping sync.";
|
|
}
|
|
|
|
if (env.VERCEL_ENV !== "production") {
|
|
return `[Typesense] Vercel environment is "${env.VERCEL_ENV}", skipping sync.`;
|
|
}
|
|
|
|
if (env.VERCEL_GIT_COMMIT_REF !== "main") {
|
|
return `[Typesense] Branch is "${env.VERCEL_GIT_COMMIT_REF}", skipping sync.`;
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
async function main() {
|
|
const skipReason = getTypesenseSyncSkipReason(process.env);
|
|
if (skipReason) {
|
|
console.log(skipReason);
|
|
return;
|
|
}
|
|
|
|
const url = process.env.NEXT_PUBLIC_TYPESENSE_SERVER_URL;
|
|
const adminKey = process.env.TYPESENSE_ADMIN_API_KEY;
|
|
if (!url || !adminKey) {
|
|
console.warn(
|
|
"[Typesense] env vars not set after skip check, skipping sync.",
|
|
);
|
|
return;
|
|
}
|
|
|
|
const filePath = ".next/server/app/api/docs/static.json.body";
|
|
if (!fs.existsSync(filePath)) {
|
|
throw new Error("Typesense build output was not found.");
|
|
}
|
|
|
|
const serverUrl = new URL(url);
|
|
const content = fs.readFileSync(filePath, "utf8");
|
|
const records = JSON.parse(content) as DocumentRecord[];
|
|
if (records.length === 0) {
|
|
throw new Error("Typesense build output contains no records.");
|
|
}
|
|
|
|
const client = new Client({
|
|
nodes: [
|
|
{
|
|
host: serverUrl.hostname,
|
|
port:
|
|
Number(serverUrl.port) ||
|
|
(serverUrl.protocol === "https:" ? 443 : 80),
|
|
protocol: serverUrl.protocol.replace(":", ""),
|
|
},
|
|
],
|
|
apiKey: adminKey,
|
|
connectionTimeoutSeconds: 30,
|
|
});
|
|
|
|
await sync(client, getTypesenseSyncOptions(records));
|
|
const collection = await client
|
|
.collections(typesenseCollectionName)
|
|
.retrieve();
|
|
if (collection.num_documents === 0) {
|
|
throw new Error("Typesense search index is empty after sync.");
|
|
}
|
|
|
|
console.log(`[Typesense] search updated: ${records.length} records`);
|
|
}
|
|
|
|
if (import.meta.main) {
|
|
await main();
|
|
}
|