Skip to content

Commit 75d8635

Browse files
authored
fix: correct webhook url on agent settings page (#232)
1 parent 648f442 commit 75d8635

6 files changed

Lines changed: 42 additions & 73 deletions

File tree

internal/api/src/routes/agents/setup-slack.test.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@ const serve = () => {
1010
bindings: {
1111
accessUrl: new URL("https://test.blink.so"),
1212
matchRequestHost: undefined,
13-
createRequestURL: undefined,
13+
createRequestURL: (id) =>
14+
new URL(`https://test.blink.so/api/webhook/${id}`),
1415
},
1516
});
1617
};

internal/api/src/routes/devhook.test.ts

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -13,21 +13,6 @@ test("devhook url with createRequestURL", async () => {
1313
);
1414
});
1515

16-
test("devhook url with path-based routing", async () => {
17-
const { helpers, bindings } = await serve({
18-
bindings: {
19-
createRequestURL: undefined,
20-
},
21-
});
22-
const { client } = await helpers.createUser();
23-
24-
const id = crypto.randomUUID();
25-
26-
const url = await client.devhook.getUrl(id);
27-
const expectedUrl = new URL(`api/webhook/${id}`, bindings.accessUrl);
28-
expect(url).toBe(expectedUrl.toString());
29-
});
30-
3116
test("devhook routes require auth by default", async () => {
3217
const { url } = await serve();
3318
const id = crypto.randomUUID();

internal/api/src/server-helper.ts

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -77,18 +77,17 @@ export const createWebhookURL = (
7777
requestId: string,
7878
path: string
7979
): string => {
80-
// Normalize path to always start with /
81-
const normalizedPath = path.startsWith("/") ? path : `/${path}`;
82-
83-
if (env.createRequestURL) {
84-
const baseUrl = env.createRequestURL(requestId);
85-
return new URL(normalizedPath, baseUrl).toString();
80+
if (!env.createRequestURL) {
81+
throw new Error(
82+
"createRequestURL is not configured - unable to create webhook URL"
83+
);
8684
}
87-
88-
// Path-based webhook mode: /api/webhook/{request_id}/{path}
89-
const baseUrl = getAccessUrlBase(env.accessUrl);
90-
return new URL(
91-
`api/webhook/${requestId}${normalizedPath}`,
92-
baseUrl
93-
).toString();
85+
// Normalize path to never start with /
86+
const normalizedPath = path.replace(/^\/+/, "");
87+
const baseUrl = env.createRequestURL(requestId);
88+
// Ensure the base URL ends with /
89+
if (!baseUrl.pathname.endsWith("/")) {
90+
baseUrl.pathname += "/";
91+
}
92+
return new URL(normalizedPath, baseUrl).toString();
9493
};

internal/site/app/(app)/[organization]/layout.tsx

Lines changed: 17 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
1-
import { auth } from "@/app/(auth)/auth";
2-
import { getQuerier } from "@/lib/database";
1+
import Client from "@blink.so/api";
32
import * as convert from "@blink.so/database/convert";
43
import { notFound, redirect } from "next/navigation";
54
import { cache } from "react";
5+
import { auth, getSessionToken } from "@/app/(auth)/auth";
6+
import { getQuerier } from "@/lib/database";
67

78
export default async function OrganizationLayout({
89
children,
@@ -29,7 +30,7 @@ export const getOrganization = cache(
2930
return notFound();
3031
}
3132
const baseURL = new URL(
32-
process.env.NEXT_PUBLIC_BASE_URL! ?? "http://localhost:3000"
33+
process.env.NEXT_PUBLIC_BASE_URL! ?? "http://localhost:3005"
3334
);
3435
return convert.organization(baseURL, organization);
3536
}
@@ -46,7 +47,7 @@ export const getOrganizationByID = cache(
4647
return notFound();
4748
}
4849
const baseURL = new URL(
49-
process.env.NEXT_PUBLIC_BASE_URL! ?? "http://localhost:3000"
50+
process.env.NEXT_PUBLIC_BASE_URL! ?? "http://localhost:3005"
5051
);
5152
return convert.organization(baseURL, organization);
5253
}
@@ -74,51 +75,26 @@ export const getAgent = cache(
7475
export const getAgentOrNull = cache(
7576
async (organizationName: string, agentName: string) => {
7677
const session = await auth();
78+
const token = await getSessionToken();
79+
const baseURL = process.env.NEXT_PUBLIC_BASE_URL ?? "http://localhost:3005";
80+
const client = new Client({
81+
baseURL,
82+
authToken: token,
83+
});
7784
const userID = session?.user?.id;
7885
const db = await getQuerier();
79-
const agent = await db.selectAgentByNameForUser({
86+
const agentFromDB = await db.selectAgentByNameForUser({
8087
organizationName,
8188
agentName,
8289
userID,
8390
});
84-
if (!agent) {
91+
if (!agentFromDB) {
8592
return null;
8693
}
87-
// Get the production deployment target's request_id
88-
const productionTarget = await db.selectAgentDeploymentTargetByName(
89-
agent.id,
90-
"production"
91-
);
92-
const requestURL = productionTarget?.request_id
93-
? new URL(`https://${productionTarget.request_id}.blink.host/`)
94-
: undefined;
95-
96-
// Get user permission for the agent
97-
let userPermission: "read" | "write" | "admin" | undefined;
98-
if (userID) {
99-
const org = await db.selectOrganizationForUser({
100-
organizationID: agent.organization_id,
101-
userID,
102-
});
103-
// Org owners and admins get admin permission
104-
if (
105-
org?.membership &&
106-
(org.membership.role === "owner" || org.membership.role === "admin")
107-
) {
108-
userPermission = "admin";
109-
} else {
110-
userPermission = await db.getAgentPermissionForUser({
111-
agentId: agent.id,
112-
userId: userID,
113-
orgRole: org?.membership?.role,
114-
});
115-
// If permission is undefined, user doesn't have access
116-
if (userPermission === undefined) {
117-
return null;
118-
}
119-
}
94+
const agent = await client.agents.get(agentFromDB.id);
95+
if (!agent) {
96+
return null;
12097
}
121-
122-
return convert.agent(agent, requestURL, userPermission);
98+
return agent;
12399
}
124100
);

internal/site/app/(auth)/auth.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,13 +27,17 @@ declare module "next-auth" {
2727
}
2828
}
2929

30+
export async function getSessionToken() {
31+
const cookieStore = await cookies();
32+
return cookieStore.get(SESSION_COOKIE_NAME)?.value;
33+
}
34+
3035
/**
3136
* Server-side auth helper function that decodes session from cookies.
3237
* This replaces the NextAuth auth() function.
3338
*/
3439
export async function auth() {
35-
const cookieStore = await cookies();
36-
const token = cookieStore.get(SESSION_COOKIE_NAME)?.value;
40+
const token = await getSessionToken();
3741

3842
if (!token) return null;
3943

packages/server/src/devhook.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { Worker as DevhookWorker } from "@blink.so/compute-protocol-worker";
44
import type Querier from "@blink.so/database/querier";
55
import { validate as uuidValidate } from "uuid";
66
import { WebSocket, WebSocketServer } from "ws";
7+
import { getAccessUrlBase } from "../../../internal/api/src/server-helper";
78

89
type DevhookSession = {
910
id: string;
@@ -72,7 +73,10 @@ export const createDevhookSupport = (opts: {
7273
url.hostname = `${id}.${wildcard.baseHost}`;
7374
return url;
7475
}
75-
: undefined;
76+
: (id: string): URL => {
77+
const baseUrl = getAccessUrlBase(accessUrl);
78+
return new URL(`api/webhook/${id}/`, baseUrl);
79+
};
7680

7781
const toUint8Array = (data: WebSocket.RawData): Uint8Array => {
7882
if (Array.isArray(data)) {

0 commit comments

Comments
 (0)