refactor(search): read OPENSEARCH_* env per call
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:
Julien Calixte
2026-06-07 22:23:36 +02:00
parent 6159ec00e0
commit 02f3139f46

View File

@@ -1,21 +1,19 @@
import type { API } from "@opensearch-project/opensearch"; import type { API } from "@opensearch-project/opensearch";
import { log } from "../log.ts"; 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 MAX_LIMIT = 100;
const enabled = (): boolean => { const openSearchUrl = (): string | undefined => Deno.env.get("OPENSEARCH_URL");
if (!OPENSEARCH_URL) return false; const openSearchIndex = (): string =>
return true; Deno.env.get("OPENSEARCH_INDEX") ?? "notes";
};
const enabled = (): boolean => Boolean(openSearchUrl());
const authHeaders = (): Record<string, string> => { const authHeaders = (): Record<string, string> => {
if (OPENSEARCH_USERNAME && OPENSEARCH_PASSWORD) { const username = Deno.env.get("OPENSEARCH_USERNAME");
const creds = btoa(`${OPENSEARCH_USERNAME}:${OPENSEARCH_PASSWORD}`); const password = Deno.env.get("OPENSEARCH_PASSWORD");
if (username && password) {
const creds = btoa(`${username}:${password}`);
return { Authorization: `Basic ${creds}` }; return { Authorization: `Basic ${creds}` };
} }
return {}; return {};
@@ -29,7 +27,7 @@ const request = async (
path: string, path: string,
body?: unknown, body?: unknown,
): Promise<Response> => { ): Promise<Response> => {
const url = `${OPENSEARCH_URL}${path}`; const url = `${openSearchUrl()}${path}`;
const headers: Record<string, string> = { ...authHeaders() }; const headers: Record<string, string> = { ...authHeaders() };
if (body !== undefined) headers["Content-Type"] = "application/json"; if (body !== undefined) headers["Content-Type"] = "application/json";
return await fetch(url, { return await fetch(url, {
@@ -59,11 +57,12 @@ const indexMappings = {
export const ensureIndex = async (): Promise<void> => { export const ensureIndex = async (): Promise<void> => {
if (!enabled()) return; if (!enabled()) return;
const head = await request("HEAD", `/${OPENSEARCH_INDEX}`); const index = openSearchIndex();
const head = await request("HEAD", `/${index}`);
if (head.status === 200) return; if (head.status === 200) return;
const res = await request("PUT", `/${OPENSEARCH_INDEX}`, indexMappings); const res = await request("PUT", `/${index}`, indexMappings);
if (res.ok) { if (res.ok) {
log(`[opensearch] created index ${OPENSEARCH_INDEX}`); log(`[opensearch] created index ${index}`);
return; return;
} }
const text = await res.text(); const text = await res.text();
@@ -96,7 +95,7 @@ export const indexNote = async (note: IndexedNote): Promise<void> => {
}; };
const res = await request( const res = await request(
"PUT", "PUT",
`/${OPENSEARCH_INDEX}/_doc/${docId(note.did, note.rkey)}`, `/${openSearchIndex()}/_doc/${docId(note.did, note.rkey)}`,
doc, doc,
); );
if (!res.ok) { if (!res.ok) {
@@ -114,7 +113,7 @@ export const removeNote = async (
if (!enabled()) return; if (!enabled()) return;
const res = await request( const res = await request(
"DELETE", "DELETE",
`/${OPENSEARCH_INDEX}/_doc/${docId(did, rkey)}`, `/${openSearchIndex()}/_doc/${docId(did, rkey)}`,
); );
if (!res.ok && res.status !== 404) { if (!res.ok && res.status !== 404) {
const text = await res.text(); const text = await res.text();
@@ -219,7 +218,7 @@ export const searchNotes = async (
...(searchAfter ? { search_after: searchAfter } : {}), ...(searchAfter ? { search_after: searchAfter } : {}),
}; };
const res = await request("POST", `/${OPENSEARCH_INDEX}/_search`, body); const res = await request("POST", `/${openSearchIndex()}/_search`, body);
if (!res.ok) { if (!res.ok) {
const text = await res.text(); const text = await res.text();
throw new Error(`Search failed: ${res.status} ${text}`); throw new Error(`Search failed: ${res.status} ${text}`);