76 lines
2.3 KiB
TypeScript
76 lines
2.3 KiB
TypeScript
|
|
/**
|
||
|
|
* strfry.ts — strfry relay HTTP client
|
||
|
|
*
|
||
|
|
* Provides `injectEvent(rawEventJson)` which POSTs a raw NIP-01 event to
|
||
|
|
* strfry's HTTP import endpoint, making it visible to relay subscribers.
|
||
|
|
*
|
||
|
|
* Used by ModerationService.decide() (approved events) and the relay policy
|
||
|
|
* handler (elite events that bypass the queue).
|
||
|
|
*
|
||
|
|
* STRFRY_URL env var: base URL of the strfry relay HTTP API.
|
||
|
|
* Defaults to "http://strfry:7777" (Docker internal network).
|
||
|
|
* In Replit dev the relay is not running — errors are logged and swallowed.
|
||
|
|
*/
|
||
|
|
|
||
|
|
import { makeLogger } from "./logger.js";
|
||
|
|
|
||
|
|
const logger = makeLogger("strfry");
|
||
|
|
|
||
|
|
const STRFRY_URL = (process.env["STRFRY_URL"] ?? "http://strfry:7777").replace(/\/$/, "");
|
||
|
|
const INJECT_TIMEOUT_MS = 5000;
|
||
|
|
|
||
|
|
export interface InjectResult {
|
||
|
|
ok: boolean;
|
||
|
|
error?: string;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Inject a raw NIP-01 event JSON string into strfry via the HTTP import API.
|
||
|
|
* strfry's POST /import accepts newline-delimited JSON events.
|
||
|
|
*
|
||
|
|
* Returns { ok: true } on success.
|
||
|
|
* Returns { ok: false, error } on failure (does NOT throw — callers are
|
||
|
|
* responsible for deciding whether to retry or surface the failure).
|
||
|
|
*/
|
||
|
|
export async function injectEvent(rawEventJson: string): Promise<InjectResult> {
|
||
|
|
const url = `${STRFRY_URL}/import`;
|
||
|
|
|
||
|
|
let response: Response;
|
||
|
|
try {
|
||
|
|
const controller = new AbortController();
|
||
|
|
const timeout = setTimeout(() => controller.abort(), INJECT_TIMEOUT_MS);
|
||
|
|
|
||
|
|
response = await fetch(url, {
|
||
|
|
method: "POST",
|
||
|
|
headers: { "Content-Type": "application/x-ndjson" },
|
||
|
|
body: rawEventJson + "\n",
|
||
|
|
signal: controller.signal,
|
||
|
|
});
|
||
|
|
|
||
|
|
clearTimeout(timeout);
|
||
|
|
} catch (err) {
|
||
|
|
const msg = err instanceof Error ? err.message : String(err);
|
||
|
|
logger.warn("strfry inject: network error", { url, error: msg });
|
||
|
|
return { ok: false, error: msg };
|
||
|
|
}
|
||
|
|
|
||
|
|
if (!response.ok) {
|
||
|
|
const body = await response.text().catch(() => "");
|
||
|
|
logger.warn("strfry inject: non-200 response", {
|
||
|
|
url,
|
||
|
|
status: response.status,
|
||
|
|
body: body.slice(0, 200),
|
||
|
|
});
|
||
|
|
return { ok: false, error: `HTTP ${response.status}: ${body.slice(0, 100)}` };
|
||
|
|
}
|
||
|
|
|
||
|
|
logger.info("strfry inject: event published", {
|
||
|
|
eventId: (() => {
|
||
|
|
try { return (JSON.parse(rawEventJson) as { id?: string }).id?.slice(0, 8) ?? "?"; }
|
||
|
|
catch { return "?"; }
|
||
|
|
})(),
|
||
|
|
});
|
||
|
|
|
||
|
|
return { ok: true };
|
||
|
|
}
|