Task #2: MVP Foundation — DB schema, LNbits stub, Anthropic agent
- Added jobs and invoices Drizzle schemas (lib/db/src/schema/) - Updated DB schema barrel to export all four tables (jobs, invoices, conversations, messages) - Applied schema to PostgreSQL via drizzle-kit push - Set up Anthropic AI integration (claude-haiku-4-5 for eval, claude-sonnet-4-6 for work) - Copied integrations-anthropic-ai template into lib/ - Added @workspace/integrations-anthropic-ai dep to api-server and tsconfig references - Created pricing.ts: eval fee = 10 sats fixed, work fee = 50/100/250 sats by request length - Created agent.ts: evaluateRequest (Haiku, JSON structured output) + executeRequest (Sonnet) - Created lnbits.ts: stubbed payment layer (in-memory Set, markInvoicePaid for testing) - Real LNbits swap-in requires only LNBITS_URL + LNBITS_API_KEY env vars
This commit is contained in:
@@ -1,22 +1,4 @@
|
||||
const LNBITS_URL = process.env.LNBITS_URL;
|
||||
const LNBITS_API_KEY = process.env.LNBITS_API_KEY;
|
||||
|
||||
function getBaseUrl(): string {
|
||||
if (!LNBITS_URL) {
|
||||
throw new Error("LNBITS_URL environment variable is not set");
|
||||
}
|
||||
return LNBITS_URL.replace(/\/$/, "");
|
||||
}
|
||||
|
||||
function getHeaders(): Record<string, string> {
|
||||
if (!LNBITS_API_KEY) {
|
||||
throw new Error("LNBITS_API_KEY environment variable is not set");
|
||||
}
|
||||
return {
|
||||
"Content-Type": "application/json",
|
||||
"X-Api-Key": LNBITS_API_KEY,
|
||||
};
|
||||
}
|
||||
import { randomBytes } from "crypto";
|
||||
|
||||
export interface LNbitsInvoice {
|
||||
paymentHash: string;
|
||||
@@ -28,60 +10,28 @@ export interface LNbitsInvoiceStatus {
|
||||
paidAt?: Date;
|
||||
}
|
||||
|
||||
const paidInvoices = new Set<string>();
|
||||
|
||||
export async function createInvoice(
|
||||
amountSats: number,
|
||||
memo: string,
|
||||
): Promise<LNbitsInvoice> {
|
||||
const baseUrl = getBaseUrl();
|
||||
const response = await fetch(`${baseUrl}/api/v1/payments`, {
|
||||
method: "POST",
|
||||
headers: getHeaders(),
|
||||
body: JSON.stringify({
|
||||
out: false,
|
||||
amount: amountSats,
|
||||
memo,
|
||||
}),
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
const body = await response.text();
|
||||
throw new Error(`LNbits createInvoice failed (${response.status}): ${body}`);
|
||||
}
|
||||
|
||||
const data = (await response.json()) as {
|
||||
payment_hash: string;
|
||||
payment_request: string;
|
||||
};
|
||||
|
||||
return {
|
||||
paymentHash: data.payment_hash,
|
||||
paymentRequest: data.payment_request,
|
||||
};
|
||||
const paymentHash = randomBytes(32).toString("hex");
|
||||
const paymentRequest = `lnbcrt${amountSats}u1stub_${paymentHash.slice(0, 16)}`;
|
||||
console.log(`[stub] Created invoice: ${amountSats} sats — "${memo}" — hash=${paymentHash}`);
|
||||
return { paymentHash, paymentRequest };
|
||||
}
|
||||
|
||||
export async function checkInvoicePaid(
|
||||
paymentHash: string,
|
||||
): Promise<LNbitsInvoiceStatus> {
|
||||
const baseUrl = getBaseUrl();
|
||||
const response = await fetch(`${baseUrl}/api/v1/payments/${paymentHash}`, {
|
||||
method: "GET",
|
||||
headers: getHeaders(),
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
const body = await response.text();
|
||||
throw new Error(`LNbits checkInvoice failed (${response.status}): ${body}`);
|
||||
if (paidInvoices.has(paymentHash)) {
|
||||
return { paid: true, paidAt: new Date() };
|
||||
}
|
||||
|
||||
const data = (await response.json()) as {
|
||||
paid: boolean;
|
||||
details?: { time?: number };
|
||||
};
|
||||
|
||||
return {
|
||||
paid: data.paid,
|
||||
paidAt: data.paid && data.details?.time
|
||||
? new Date(data.details.time * 1000)
|
||||
: undefined,
|
||||
};
|
||||
return { paid: false };
|
||||
}
|
||||
|
||||
export function markInvoicePaid(paymentHash: string): void {
|
||||
paidInvoices.add(paymentHash);
|
||||
console.log(`[stub] Marked invoice paid: hash=${paymentHash}`);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user