Skip to content

Commit d5d27f5

Browse files
committed
hyperblogs
1 parent da80c05 commit d5d27f5

File tree

3 files changed

+98
-47
lines changed

3 files changed

+98
-47
lines changed
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
/**
2+
* Entity lookup by UUID API route
3+
* Direct entity fetch without expensive delve queries
4+
*/
5+
import { NextRequest, NextResponse } from "next/server";
6+
import { config } from "@/lib/config";
7+
import { createErrorFromResponse } from "@/lib/types/errors";
8+
9+
/**
10+
* GET /api/knowledge_graph/entity/[uuid]
11+
*
12+
* Fetches a single entity by UUID from the knowledge graph
13+
*/
14+
export async function GET(request: NextRequest, { params }: { params: Promise<{ uuid: string }> }) {
15+
try {
16+
const { uuid } = await params;
17+
18+
if (!uuid || typeof uuid !== "string") {
19+
return NextResponse.json({ error: "Invalid uuid parameter" }, { status: 400 });
20+
}
21+
22+
// Get optional bonfire_id from query params
23+
const searchParams = request.nextUrl.searchParams;
24+
const bonfireId = searchParams.get("bonfire_id");
25+
26+
// Build backend URL
27+
const backendUrl = new URL(`${config.delve.apiUrl}/knowledge_graph/entity/${uuid}`);
28+
if (bonfireId) {
29+
backendUrl.searchParams.append("bonfire_id", bonfireId);
30+
}
31+
32+
console.log(`Fetching entity by UUID: ${backendUrl.toString()}`);
33+
34+
const response = await fetch(backendUrl.toString(), {
35+
method: "GET",
36+
headers: { "Content-Type": "application/json" },
37+
signal: AbortSignal.timeout(config.delve.timeout),
38+
});
39+
40+
if (!response.ok) {
41+
const error = await createErrorFromResponse(response);
42+
return NextResponse.json({ error: error.message, details: error.details }, { status: response.status });
43+
}
44+
45+
const data = await response.json();
46+
return NextResponse.json(data, { status: 200 });
47+
} catch (error) {
48+
console.error("Error fetching entity:", error);
49+
50+
if (error instanceof Error && error.name === "TimeoutError") {
51+
return NextResponse.json({ error: "Request timeout" }, { status: 503 });
52+
}
53+
54+
return NextResponse.json(
55+
{ error: "Internal server error", details: error instanceof Error ? error.message : String(error) },
56+
{ status: 500 },
57+
);
58+
}
59+
}

packages/nextjs/components/DataRoomCard.tsx

Lines changed: 17 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -40,9 +40,9 @@ export const DataRoomCard: React.FC<DataRoomCardProps> = ({ microsub, bonfires,
4040
return bonfire ? bonfire.name : truncateAddress(microsub.bonfire_id, 6);
4141
}, [microsub.bonfire_id, bonfires]);
4242

43-
// Fetch center node info from the graph
43+
// Fetch center node info by UUID (direct lookup, no delve query)
4444
const fetchCenterNodeInfo = useCallback(async () => {
45-
if (!microsub.center_node_uuid || !microsub.bonfire_id) return;
45+
if (!microsub.center_node_uuid) return;
4646

4747
// Abort any existing request
4848
if (centerNodeAbortRef.current) {
@@ -53,35 +53,31 @@ export const DataRoomCard: React.FC<DataRoomCardProps> = ({ microsub, bonfires,
5353
setCenterNodeLoading(true);
5454

5555
try {
56-
const response = await fetch(`/api/bonfires/${microsub.bonfire_id}/preview`, {
57-
method: "POST",
56+
// Direct entity lookup by UUID - much cheaper than delve
57+
const url = new URL(`/api/knowledge_graph/entity/${microsub.center_node_uuid}`, window.location.origin);
58+
if (microsub.bonfire_id) {
59+
url.searchParams.append("bonfire_id", microsub.bonfire_id);
60+
}
61+
62+
const response = await fetch(url.toString(), {
63+
method: "GET",
5864
headers: { "Content-Type": "application/json" },
59-
body: JSON.stringify({
60-
query: "",
61-
num_results: 10,
62-
center_node_uuid: microsub.center_node_uuid,
63-
}),
6465
signal: centerNodeAbortRef.current.signal,
6566
});
6667

6768
if (!response.ok) {
6869
throw new Error(`Failed to fetch center node: ${response.statusText}`);
6970
}
7071

71-
const data: DelveResponse = await response.json();
72+
const entity = await response.json();
7273

73-
// Find the center node in the returned entities by matching UUID
74-
const centerNode = (data.entities || []).find(
75-
entity => entity.uuid === microsub.center_node_uuid || entity.id === microsub.center_node_uuid,
76-
);
77-
78-
if (centerNode) {
74+
if (entity) {
7975
setCenterNodeInfo({
80-
uuid: centerNode.uuid || centerNode.id,
81-
name: centerNode.name || "Unknown Node",
82-
entity_type: centerNode.entity_type || centerNode.type,
83-
summary: centerNode.summary || centerNode.description,
84-
labels: centerNode.labels,
76+
uuid: entity.uuid || entity.id || microsub.center_node_uuid,
77+
name: entity.name || "Unknown Node",
78+
entity_type: entity.entity_type || entity.type || "unknown",
79+
summary: entity.summary || entity.description || "",
80+
labels: entity.labels || [],
8581
});
8682
}
8783
} catch (err) {

packages/nextjs/components/DataRoomMarketplaceCard.tsx

Lines changed: 22 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -182,9 +182,9 @@ export function DataRoomMarketplaceCard({
182182
}
183183
};
184184

185-
// Fetch center node info from the graph
185+
// Fetch center node info by UUID (direct lookup, no delve query)
186186
const fetchCenterNodeInfo = async () => {
187-
if (!dataroom.center_node_uuid || !dataroom.bonfire_id) return;
187+
if (!dataroom.center_node_uuid) return;
188188

189189
// Abort any existing request
190190
if (centerNodeAbortRef.current) {
@@ -195,39 +195,35 @@ export function DataRoomMarketplaceCard({
195195
setCenterNodeLoading(true);
196196

197197
try {
198-
const response = await fetch(`/api/bonfires/${dataroom.bonfire_id}/preview`, {
199-
method: "POST",
198+
// Direct entity lookup by UUID - much cheaper than delve
199+
const url = new URL(`/api/knowledge_graph/entity/${dataroom.center_node_uuid}`, window.location.origin);
200+
if (dataroom.bonfire_id) {
201+
url.searchParams.append("bonfire_id", dataroom.bonfire_id);
202+
}
203+
204+
const response = await fetch(url.toString(), {
205+
method: "GET",
200206
headers: { "Content-Type": "application/json" },
201-
body: JSON.stringify({
202-
query: "",
203-
num_results: 10,
204-
center_node_uuid: dataroom.center_node_uuid,
205-
}),
206207
signal: centerNodeAbortRef.current.signal,
207208
});
208209

209210
if (!response.ok) {
210211
throw new Error(`Failed to fetch center node: ${response.statusText}`);
211212
}
212213

213-
const data = await response.json();
214+
const entity = await response.json();
214215

215-
// Find the center node in the returned entities by matching UUID
216-
const centerNode = (data.entities || []).find(
217-
(entity: any) => entity.uuid === dataroom.center_node_uuid || entity.id === dataroom.center_node_uuid,
218-
);
219-
220-
if (centerNode) {
216+
if (entity) {
221217
setCenterNodeInfo({
222-
uuid: centerNode.uuid || centerNode.id,
223-
name: centerNode.name || "Unknown Node",
224-
entity_type: centerNode.entity_type || centerNode.type,
225-
summary: centerNode.summary || centerNode.description,
226-
labels: centerNode.labels,
218+
uuid: entity.uuid || entity.id || dataroom.center_node_uuid,
219+
name: entity.name || "Unknown Node",
220+
entity_type: entity.entity_type || entity.type || "unknown",
221+
summary: entity.summary || entity.description || "",
222+
labels: entity.labels || [],
227223
});
228224
}
229-
} catch (err: any) {
230-
if (err.name === "AbortError") return;
225+
} catch (err: unknown) {
226+
if (err instanceof Error && err.name === "AbortError") return;
231227
console.error("Failed to fetch center node info:", err);
232228
} finally {
233229
setCenterNodeLoading(false);
@@ -251,13 +247,13 @@ export function DataRoomMarketplaceCard({
251247
}
252248
};
253249

254-
// Fetch center node info on mount if center_node_uuid exists
250+
// Fetch center node info only when preview is expanded (not on mount)
255251
useEffect(() => {
256-
if (dataroom.center_node_uuid && !centerNodeInfo) {
252+
if (isPreviewExpanded && dataroom.center_node_uuid && !centerNodeInfo && !centerNodeLoading) {
257253
fetchCenterNodeInfo();
258254
}
259255
// eslint-disable-next-line react-hooks/exhaustive-deps
260-
}, [dataroom.center_node_uuid]);
256+
}, [isPreviewExpanded, dataroom.center_node_uuid]);
261257

262258
// Cleanup on unmount
263259
useEffect(() => {

0 commit comments

Comments
 (0)