refactor(search): read OPENSEARCH_* env per call
Some checks failed
CI / check (push) Failing after 12s
Some checks failed
CI / check (push) Failing after 12s
Tests can't override values captured at module load because ES imports hoist before any Deno.env.set call. Reading env on each helper invocation makes the module trivially testable and has no production cost (env doesn't change at runtime).
This commit is contained in:
@@ -1,21 +1,19 @@
|
||||
import type { API } from "@opensearch-project/opensearch";
|
||||
import { log } from "../log.ts";
|
||||
|
||||
const OPENSEARCH_URL = Deno.env.get("OPENSEARCH_URL");
|
||||
const OPENSEARCH_USERNAME = Deno.env.get("OPENSEARCH_USERNAME");
|
||||
const OPENSEARCH_PASSWORD = Deno.env.get("OPENSEARCH_PASSWORD");
|
||||
const OPENSEARCH_INDEX = Deno.env.get("OPENSEARCH_INDEX") ?? "notes";
|
||||
|
||||
const MAX_LIMIT = 100;
|
||||
|
||||
const enabled = (): boolean => {
|
||||
if (!OPENSEARCH_URL) return false;
|
||||
return true;
|
||||
};
|
||||
const openSearchUrl = (): string | undefined => Deno.env.get("OPENSEARCH_URL");
|
||||
const openSearchIndex = (): string =>
|
||||
Deno.env.get("OPENSEARCH_INDEX") ?? "notes";
|
||||
|
||||
const enabled = (): boolean => Boolean(openSearchUrl());
|
||||
|
||||
const authHeaders = (): Record<string, string> => {
|
||||
if (OPENSEARCH_USERNAME && OPENSEARCH_PASSWORD) {
|
||||
const creds = btoa(`${OPENSEARCH_USERNAME}:${OPENSEARCH_PASSWORD}`);
|
||||
const username = Deno.env.get("OPENSEARCH_USERNAME");
|
||||
const password = Deno.env.get("OPENSEARCH_PASSWORD");
|
||||
if (username && password) {
|
||||
const creds = btoa(`${username}:${password}`);
|
||||
return { Authorization: `Basic ${creds}` };
|
||||
}
|
||||
return {};
|
||||
@@ -29,7 +27,7 @@ const request = async (
|
||||
path: string,
|
||||
body?: unknown,
|
||||
): Promise<Response> => {
|
||||
const url = `${OPENSEARCH_URL}${path}`;
|
||||
const url = `${openSearchUrl()}${path}`;
|
||||
const headers: Record<string, string> = { ...authHeaders() };
|
||||
if (body !== undefined) headers["Content-Type"] = "application/json";
|
||||
return await fetch(url, {
|
||||
@@ -59,11 +57,12 @@ const indexMappings = {
|
||||
|
||||
export const ensureIndex = async (): Promise<void> => {
|
||||
if (!enabled()) return;
|
||||
const head = await request("HEAD", `/${OPENSEARCH_INDEX}`);
|
||||
const index = openSearchIndex();
|
||||
const head = await request("HEAD", `/${index}`);
|
||||
if (head.status === 200) return;
|
||||
const res = await request("PUT", `/${OPENSEARCH_INDEX}`, indexMappings);
|
||||
const res = await request("PUT", `/${index}`, indexMappings);
|
||||
if (res.ok) {
|
||||
log(`[opensearch] created index ${OPENSEARCH_INDEX}`);
|
||||
log(`[opensearch] created index ${index}`);
|
||||
return;
|
||||
}
|
||||
const text = await res.text();
|
||||
@@ -96,7 +95,7 @@ export const indexNote = async (note: IndexedNote): Promise<void> => {
|
||||
};
|
||||
const res = await request(
|
||||
"PUT",
|
||||
`/${OPENSEARCH_INDEX}/_doc/${docId(note.did, note.rkey)}`,
|
||||
`/${openSearchIndex()}/_doc/${docId(note.did, note.rkey)}`,
|
||||
doc,
|
||||
);
|
||||
if (!res.ok) {
|
||||
@@ -114,7 +113,7 @@ export const removeNote = async (
|
||||
if (!enabled()) return;
|
||||
const res = await request(
|
||||
"DELETE",
|
||||
`/${OPENSEARCH_INDEX}/_doc/${docId(did, rkey)}`,
|
||||
`/${openSearchIndex()}/_doc/${docId(did, rkey)}`,
|
||||
);
|
||||
if (!res.ok && res.status !== 404) {
|
||||
const text = await res.text();
|
||||
@@ -219,7 +218,7 @@ export const searchNotes = async (
|
||||
...(searchAfter ? { search_after: searchAfter } : {}),
|
||||
};
|
||||
|
||||
const res = await request("POST", `/${OPENSEARCH_INDEX}/_search`, body);
|
||||
const res = await request("POST", `/${openSearchIndex()}/_search`, body);
|
||||
if (!res.ok) {
|
||||
const text = await res.text();
|
||||
throw new Error(`Search failed: ${res.status} ${text}`);
|
||||
|
||||
Reference in New Issue
Block a user