Skip to content

Commit 1bd8e40

Browse files
committed
feat
1 parent e94d535 commit 1bd8e40

8 files changed

Lines changed: 363 additions & 37 deletions

File tree

app/api/countries/conflicts/route.ts

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
import { NextResponse } from "next/server";
22
import { getCountryConflicts, streamCountryConflicts } from "@/lib/valyu";
3+
import { isSelfHostedMode } from "@/lib/app-mode";
34

45
export const dynamic = "force-dynamic";
56

67
export async function GET(request: Request) {
78
const { searchParams } = new URL(request.url);
89
const country = searchParams.get("country");
910
const stream = searchParams.get("stream") === "true";
11+
const accessToken = searchParams.get("accessToken");
1012

1113
if (!country) {
1214
return NextResponse.json(
@@ -15,14 +17,23 @@ export async function GET(request: Request) {
1517
);
1618
}
1719

20+
// In valyu mode, require user token
21+
const selfHosted = isSelfHostedMode();
22+
if (!selfHosted && !accessToken) {
23+
return NextResponse.json(
24+
{ error: "Authentication required", requiresReauth: true },
25+
{ status: 401 }
26+
);
27+
}
28+
1829
// Streaming mode - use Server-Sent Events
1930
if (stream) {
2031
const encoder = new TextEncoder();
2132

2233
const readable = new ReadableStream({
2334
async start(controller) {
2435
try {
25-
for await (const chunk of streamCountryConflicts(country)) {
36+
for await (const chunk of streamCountryConflicts(country, { accessToken: accessToken || undefined })) {
2637
const data = `data: ${JSON.stringify(chunk)}\n\n`;
2738
controller.enqueue(encoder.encode(data));
2839
}
@@ -49,7 +60,7 @@ export async function GET(request: Request) {
4960

5061
// Non-streaming mode - return full response
5162
try {
52-
const result = await getCountryConflicts(country);
63+
const result = await getCountryConflicts(country, { accessToken: accessToken || undefined });
5364

5465
return NextResponse.json({
5566
country,

app/api/deepresearch/[taskId]/route.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,15 @@ export async function GET(
7171
const selfHosted = isSelfHostedMode();
7272
let statusData: any;
7373

74-
// Use OAuth proxy if user is signed in and not self-hosted
74+
// Valyu mode requires auth
75+
if (!selfHosted && !accessToken) {
76+
return NextResponse.json(
77+
{ error: "Authentication required", requiresReauth: true },
78+
{ status: 401 }
79+
);
80+
}
81+
82+
// Use OAuth proxy in valyu mode
7583
if (!selfHosted && accessToken) {
7684
statusData = await getStatusViaProxy(taskId, accessToken);
7785
if (statusData.error) {

app/api/deepresearch/route.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,15 @@ export async function POST(request: Request) {
102102

103103
const selfHosted = isSelfHostedMode();
104104

105-
// Use OAuth proxy if user is signed in and not self-hosted
105+
// Valyu mode requires auth
106+
if (!selfHosted && !accessToken) {
107+
return NextResponse.json(
108+
{ error: "Authentication required", requiresReauth: true },
109+
{ status: 401 }
110+
);
111+
}
112+
113+
// Use OAuth proxy in valyu mode
106114
if (!selfHosted && accessToken) {
107115
const result = await createTaskViaProxy(topic, accessToken);
108116
if (result.error) {

app/api/entities/route.ts

Lines changed: 27 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { NextResponse } from "next/server";
22
import { getEntityResearch, deepResearch, searchEntityLocations, streamEntityResearch } from "@/lib/valyu";
3+
import { isSelfHostedMode } from "@/lib/app-mode";
34

45
export const dynamic = "force-dynamic";
56
import { geocodeLocationsFromText } from "@/lib/geocoding";
@@ -9,6 +10,7 @@ export async function GET(request: Request) {
910
const { searchParams } = new URL(request.url);
1011
const name = searchParams.get("name");
1112
const stream = searchParams.get("stream") === "true";
13+
const accessToken = searchParams.get("accessToken");
1214

1315
if (!name) {
1416
return NextResponse.json(
@@ -17,14 +19,23 @@ export async function GET(request: Request) {
1719
);
1820
}
1921

22+
// In valyu mode, require authentication
23+
const selfHosted = isSelfHostedMode();
24+
if (!selfHosted && !accessToken) {
25+
return NextResponse.json(
26+
{ error: "Authentication required", requiresReauth: true },
27+
{ status: 401 }
28+
);
29+
}
30+
2031
// Streaming mode - use Server-Sent Events
2132
if (stream) {
2233
const encoder = new TextEncoder();
2334

2435
const readable = new ReadableStream({
2536
async start(controller) {
2637
try {
27-
for await (const chunk of streamEntityResearch(name)) {
38+
for await (const chunk of streamEntityResearch(name, { accessToken: accessToken || undefined })) {
2839
const data = `data: ${JSON.stringify(chunk)}\n\n`;
2940
controller.enqueue(encoder.encode(data));
3041
}
@@ -53,7 +64,7 @@ export async function GET(request: Request) {
5364
const deep = searchParams.get("deep") === "true";
5465

5566
try {
56-
const entityData = await getEntityResearch(name);
67+
const entityData = await getEntityResearch(name, { accessToken: accessToken || undefined });
5768

5869
if (!entityData) {
5970
return NextResponse.json(
@@ -73,7 +84,7 @@ export async function GET(request: Request) {
7384
};
7485

7586
if (deep) {
76-
const research = await deepResearch(name);
87+
const research = await deepResearch(name, { accessToken: accessToken || undefined });
7788
profile.researchSummary = research.summary;
7889
}
7990

@@ -90,7 +101,7 @@ export async function GET(request: Request) {
90101
export async function POST(request: Request) {
91102
try {
92103
const body = await request.json();
93-
const { name, includeDeepResearch } = body;
104+
const { name, includeDeepResearch, accessToken } = body;
94105

95106
if (!name) {
96107
return NextResponse.json(
@@ -99,9 +110,18 @@ export async function POST(request: Request) {
99110
);
100111
}
101112

113+
// In valyu mode, require authentication
114+
const selfHosted = isSelfHostedMode();
115+
if (!selfHosted && !accessToken) {
116+
return NextResponse.json(
117+
{ error: "Authentication required", requiresReauth: true },
118+
{ status: 401 }
119+
);
120+
}
121+
102122
const [entityData, locationContent] = await Promise.all([
103-
getEntityResearch(name),
104-
searchEntityLocations(name),
123+
getEntityResearch(name, { accessToken: accessToken || undefined }),
124+
searchEntityLocations(name, { accessToken: accessToken || undefined }),
105125
]);
106126

107127
if (!entityData) {
@@ -137,7 +157,7 @@ export async function POST(request: Request) {
137157
let pdfUrl = undefined;
138158

139159
if (includeDeepResearch) {
140-
const research = await deepResearch(name);
160+
const research = await deepResearch(name, { accessToken: accessToken || undefined });
141161
profile.researchSummary = research.summary;
142162
deliverables = research.deliverables;
143163
pdfUrl = research.pdfUrl;

app/api/events/route.ts

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -161,14 +161,33 @@ async function processSearchResults(
161161
export async function GET(request: Request) {
162162
const { searchParams } = new URL(request.url);
163163
const query = searchParams.get("q");
164+
const accessToken = searchParams.get("accessToken");
165+
166+
// In valyu mode, require authentication
167+
const selfHosted = isSelfHostedMode();
168+
if (!selfHosted && !accessToken) {
169+
return NextResponse.json(
170+
{ error: "Authentication required", requiresReauth: true },
171+
{ status: 401 }
172+
);
173+
}
164174

165175
try {
166176
const searchQueries = query ? [query] : THREAT_QUERIES;
177+
const tokenToUse = selfHosted ? undefined : accessToken;
167178

168179
const searchResultsArrays = await Promise.all(
169-
searchQueries.map((q) => searchEvents(q, { maxResults: 20 }))
180+
searchQueries.map((q) => searchEvents(q, { maxResults: 20, accessToken: tokenToUse || undefined }))
170181
);
171182

183+
const requiresReauth = searchResultsArrays.some((r) => r.requiresReauth);
184+
if (requiresReauth) {
185+
return NextResponse.json(
186+
{ error: "auth_error", message: "Session expired. Please sign in again.", requiresReauth: true },
187+
{ status: 401 }
188+
);
189+
}
190+
172191
const allResults = searchResultsArrays.flatMap((r) => r.results);
173192
const sortedEvents = await processSearchResults(allResults);
174193

@@ -192,6 +211,15 @@ export async function POST(request: Request) {
192211
const { queries, accessToken } = body;
193212

194213
const selfHosted = isSelfHostedMode();
214+
215+
// In valyu mode, require authentication
216+
if (!selfHosted && !accessToken) {
217+
return NextResponse.json(
218+
{ error: "Authentication required", requiresReauth: true },
219+
{ status: 401 }
220+
);
221+
}
222+
195223
const tokenToUse = selfHosted ? undefined : accessToken;
196224

197225
const searchQueries = queries && Array.isArray(queries) && queries.length > 0

app/api/reports/route.ts

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
import { NextResponse } from "next/server";
22
import { deepResearch } from "@/lib/valyu";
3+
import { isSelfHostedMode } from "@/lib/app-mode";
34

45
export const dynamic = "force-dynamic";
56

67
export async function POST(request: Request) {
78
try {
89
const body = await request.json();
9-
const { topic, type } = body;
10+
const { topic, type, accessToken } = body;
1011

1112
if (!topic) {
1213
return NextResponse.json(
@@ -15,6 +16,15 @@ export async function POST(request: Request) {
1516
);
1617
}
1718

19+
// In valyu mode, require authentication
20+
const selfHosted = isSelfHostedMode();
21+
if (!selfHosted && !accessToken) {
22+
return NextResponse.json(
23+
{ error: "Authentication required", requiresReauth: true },
24+
{ status: 401 }
25+
);
26+
}
27+
1828
let enhancedQuery = topic;
1929

2030
switch (type) {
@@ -34,7 +44,7 @@ export async function POST(request: Request) {
3444
enhancedQuery = `comprehensive analysis ${topic}`;
3545
}
3646

37-
const research = await deepResearch(enhancedQuery);
47+
const research = await deepResearch(enhancedQuery, { accessToken: accessToken || undefined });
3848

3949
return NextResponse.json({
4050
report: {

components/map/country-conflicts-modal.tsx

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import {
2020
} from "lucide-react";
2121
import { Favicon } from "@/components/ui/favicon";
2222
import { cn } from "@/lib/utils";
23+
import { useAuthStore } from "@/stores/auth-store";
2324

2425
interface CountryConflictsModalProps {
2526
country: string | null;
@@ -102,6 +103,7 @@ export function CountryConflictsModal({
102103
const [error, setError] = useState<string | null>(null);
103104
const [activeTab, setActiveTab] = useState<TabType>("current");
104105
const eventSourceRef = useRef<EventSource | null>(null);
106+
const { accessToken } = useAuthStore();
105107

106108
useEffect(() => {
107109
if (!country) {
@@ -130,9 +132,15 @@ export function CountryConflictsModal({
130132
past: { conflicts: "", sources: [] },
131133
});
132134

133-
const eventSource = new EventSource(
134-
`/api/countries/conflicts?country=${encodeURIComponent(country)}&stream=true`
135-
);
135+
// Build URL with access token if available
136+
const url = new URL(`/api/countries/conflicts`, window.location.origin);
137+
url.searchParams.set("country", country);
138+
url.searchParams.set("stream", "true");
139+
if (accessToken) {
140+
url.searchParams.set("accessToken", accessToken);
141+
}
142+
143+
const eventSource = new EventSource(url.toString());
136144
eventSourceRef.current = eventSource;
137145

138146
eventSource.onmessage = (event) => {
@@ -232,7 +240,7 @@ export function CountryConflictsModal({
232240
return () => {
233241
eventSource.close();
234242
};
235-
}, [country, onLoadingChange]);
243+
}, [country, onLoadingChange, accessToken]);
236244

237245
const isStreaming =
238246
(activeTab === "current" && isStreamingCurrent) ||

0 commit comments

Comments
 (0)