History

more debug logs

Rhys Sullivan committed 8 months ago

Commit e3f60e21 parent ede45ad7 files · +93 −110Browse files

Unified · Split

7 files
  1. apps/web/README.md +1 −7
  2. apps/web/app/(console)/tools/page.tsx +2 −33
  3. apps/web/components/tools/tools-view.tsx +0 −10
  4. apps/web/lib/control-plane/server.ts +52 −25
  5. apps/web/lib/external-origin.ts +35 −0
  6. apps/web/lib/mcp/oauth-request.ts +3 −25
  7. packages/persistence-sql/src/sql-internals.ts +0 −10
apps/web/README.md+1−7
@@ -17,21 +17,15 @@ The API route now runs the control-plane server in-process. · 16 unmodified lines
1717
1818 Database selection priority:
1919
20−- `CONTROL_PLANE_DATABASE_URL`
2120 - `DATABASE_URL`
22−- `POSTGRES_URL`
2321
2422 If none are set, fallback is local PGlite data at:
2523
26−- `CONTROL_PLANE_DATA_DIR`
2724 - default: `.executor-v2/web-state/control-plane-pgdata`
2825
29−If needed, `NEXT_PUBLIC_CONTROL_PLANE_BASE_URL` can override the browser base URL.
30−
3126 MCP install URL generation:
3227
33−- Derives from existing control-plane/frontend config.
34−- Prioritizes server-side `CONTROL_PLANE_UPSTREAM_URL` (or server/base control-plane URL) when available.
28+- Derives from existing frontend origin and deployment metadata.
3529 - In local dev with no DB URL, defaults to local PGlite-backed control-plane in this Next.js app.
3630
3731 WorkOS auth setup (optional but recommended):
apps/web/app/(console)/tools/page.tsx+2−33
@@ -1,39 +1,8 @@
11 import { ToolsView } from "../../../components/tools/tools-view";
2−
3−const normalizeOriginCandidate = (value: string | undefined): string | null => {
4− const trimmed = value?.trim();
5− if (!trimmed) {
6− return null;
7− }
8−
9− const withProtocol =
10− trimmed.startsWith("http://") || trimmed.startsWith("https://")
11− ? trimmed
12− : `https://${trimmed}`;
13−
14− try {
15− return new URL(withProtocol).origin;
16− } catch {
17− return null;
18− }
19−};
2+import { configuredExternalOriginFromEnv } from "../../../lib/external-origin";
203
214 const resolveMcpBaseUrl = (): string | null => {
22− const candidates = [
23− process.env.EXECUTOR_PUBLIC_ORIGIN,
24− process.env.NEXT_PUBLIC_APP_ORIGIN,
25− process.env.VERCEL_PROJECT_PRODUCTION_URL,
26− process.env.VERCEL_URL,
27− ];
28−
29− for (const candidate of candidates) {
30− const origin = normalizeOriginCandidate(candidate);
31− if (origin) {
32− return origin;
33− }
34− }
35−
36− return null;
5+ return configuredExternalOriginFromEnv();
376 };
387
398 const ToolsPage = () => <ToolsView mcpBaseUrl={resolveMcpBaseUrl()} />;
apps/web/components/tools/tools-view.tsx+0−10
@@ -65,9 +65,6 @@ type SourceGroup = { · 64 unmodified lines
6565 toolCount: number;
6666 };
6767
68−const configuredControlPlaneBaseUrl =
69− process.env.NEXT_PUBLIC_CONTROL_PLANE_BASE_URL?.trim() ?? "";
70−
7168 const isLocalHost = (hostname: string): boolean =>
7269 hostname === "localhost"
7370 || hostname === "127.0.0.1"
@@ -406,13 +403,6 @@ export function ToolsView(props: { · 332 unmodified lines
406403 return configured.toString();
407404 }
408405
409− if (configuredControlPlaneBaseUrl.length > 0 && /^https?:\/\//i.test(configuredControlPlaneBaseUrl)) {
410− const configured = new URL(configuredControlPlaneBaseUrl);
411− configured.pathname = "/v1/mcp";
412− configured.searchParams.set("workspaceId", workspaceId);
413− return configured.toString();
414− }
415−
416406 if (typeof window === "undefined") {
417407 return `http://127.0.0.1:8788/v1/mcp?workspaceId=${encodeURIComponent(workspaceId)}`;
418408 }
apps/web/lib/control-plane/server.ts+52−25
@@ -117,30 +117,39 @@ const toAccountScopedIds = (subject: string) => { · 116 unmodified lines
117117 };
118118
119119 const resolveDatabaseUrl = (): string | undefined => {
120− const override = trim(process.env.CONTROL_PLANE_DATABASE_URL);
121− if (override) {
122− return override;
123− }
124−
125− const candidates = [process.env.DATABASE_URL, process.env.POSTGRES_URL];
126−
127− for (const candidate of candidates) {
128− const value = trim(candidate);
129− if (value) {
130− return deriveRuntimeDatabaseUrl(value);
131− }
132− }
133−
134− return undefined;
120+ const value = trim(process.env.DATABASE_URL);
121+ return value ? deriveRuntimeDatabaseUrl(value) : undefined;
135122 };
136123
137124 const resolveControlPlaneDataDir = (): string =>
138− trim(process.env.CONTROL_PLANE_DATA_DIR) ?? defaultControlPlaneDataDir;
125+ defaultControlPlaneDataDir;
139126
140127 const resolveStateRootDir = (): string =>
141− trim(process.env.CONTROL_PLANE_STATE_ROOT_DIR) ?? defaultControlPlaneStateRootDir;
128+ defaultControlPlaneStateRootDir;
129+
130+const openApiSyncRetryDelayMs = 300;
142131
143132 const formatCause = (cause: unknown): string => {
133+ if (cause && typeof cause === "object") {
134+ const maybeError = cause as {
135+ message?: unknown;
136+ details?: unknown;
137+ };
138+
139+ const details = typeof maybeError.details === "string" ? maybeError.details.trim() : "";
140+ const message = typeof maybeError.message === "string" ? maybeError.message.trim() : "";
141+
142+ if (details.length > 0) {
143+ return message.length > 0 && message !== details
144+ ? `${message}: ${details}`
145+ : details;
146+ }
147+
148+ if (message.length > 0) {
149+ return message;
150+ }
151+ }
152+
144153 if (cause instanceof Error) {
145154 return cause.message;
146155 }
@@ -252,6 +261,18 @@ const createControlPlaneRuntime = async (): Promise<ControlPlaneRuntime> => { · 105 unmodified lines
252261 const sourceManager = makeSourceManagerService(toolArtifactStore);
253262 const baseSourcesService = makeControlPlaneSourcesService(sourceCatalog);
254263
264+ const fetchOpenApiSpec = (endpoint: string) =>
265+ Effect.tryPromise({
266+ try: () => fetchOpenApiDocument(endpoint),
267+ catch: (cause) => String(cause),
268+ }).pipe(Effect.either);
269+
270+ const refreshOpenApiTools = (input: {
271+ source: Parameters<typeof sourceManager.refreshOpenApiArtifact>[0]["source"];
272+ openApiSpec: unknown;
273+ }) =>
274+ sourceManager.refreshOpenApiArtifact(input).pipe(Effect.either);
275+
255276 const persistSourceErrorState = (source: Parameters<typeof sourceStore.upsert>[0], message: string) => {
256277 const failedSource = {
257278 ...source,
@@ -276,10 +297,11 @@ const createControlPlaneRuntime = async (): Promise<ControlPlaneRuntime> => { · 18 unmodified lines
276297 return source;
277298 }
278299
279− const openApiSpecResult = yield* Effect.tryPromise({
280− try: () => fetchOpenApiDocument(source.endpoint),
281− catch: (cause) => String(cause),
282− }).pipe(Effect.either);
300+ let openApiSpecResult = yield* fetchOpenApiSpec(source.endpoint);
301+ if (openApiSpecResult._tag === "Left") {
302+ yield* Effect.sleep(openApiSyncRetryDelayMs);
303+ openApiSpecResult = yield* fetchOpenApiSpec(source.endpoint);
304+ }
283305
284306 if (openApiSpecResult._tag === "Left") {
285307 const details = formatCause(openApiSpecResult.left);
@@ -294,12 +316,17 @@ const createControlPlaneRuntime = async (): Promise<ControlPlaneRuntime> => { · 8 unmodified lines
294316 return yield* persistSourceErrorState(source, message);
295317 }
296318
297− const refreshedResult = yield* sourceManager
298− .refreshOpenApiArtifact({
319+ let refreshedResult = yield* refreshOpenApiTools({
320+ source,
321+ openApiSpec: openApiSpecResult.right,
322+ });
323+ if (refreshedResult._tag === "Left") {
324+ yield* Effect.sleep(openApiSyncRetryDelayMs);
325+ refreshedResult = yield* refreshOpenApiTools({
299326 source,
300327 openApiSpec: openApiSpecResult.right,
301− })
302− .pipe(Effect.either);
328+ });
329+ }
303330
304331 if (refreshedResult._tag === "Left") {
305332 const details = formatCause(refreshedResult.left);
apps/web/lib/external-origin.ts+35−0
@@ -0,0 +1,35 @@
1+const normalizeOriginCandidate = (value: string | undefined): string | null => {
2+ const trimmed = value?.trim();
3+ if (!trimmed) {
4+ return null;
5+ }
6+
7+ const withProtocol =
8+ trimmed.startsWith("http://") || trimmed.startsWith("https://")
9+ ? trimmed
10+ : `https://${trimmed}`;
11+
12+ try {
13+ return new URL(withProtocol).origin;
14+ } catch {
15+ return null;
16+ }
17+};
18+
19+export const configuredExternalOriginFromEnv = (): string | null => {
20+ const candidates = [
21+ process.env.EXECUTOR_PUBLIC_ORIGIN,
22+ process.env.NEXT_PUBLIC_APP_ORIGIN,
23+ process.env.VERCEL_PROJECT_PRODUCTION_URL,
24+ process.env.VERCEL_URL,
25+ ];
26+
27+ for (const candidate of candidates) {
28+ const origin = normalizeOriginCandidate(candidate);
29+ if (origin) {
30+ return origin;
31+ }
32+ }
33+
34+ return null;
35+};
apps/web/lib/mcp/oauth-request.ts+3−25
@@ -1,3 +1,5 @@
1+import { configuredExternalOriginFromEnv } from "../external-origin";
2+
13 const firstHeaderValue = (value: string | null): string => {
24 if (!value) {
35 return "";
@@ -6,32 +8,8 @@ const firstHeaderValue = (value: string | null): string => { · 2 unmodified lines
68 return value.split(",")[0]?.trim() ?? "";
79 };
810
9−const configuredExternalOrigin = (): string | null => {
10− const configured =
11− process.env.EXECUTOR_PUBLIC_ORIGIN
12− ?? process.env.NEXT_PUBLIC_APP_ORIGIN
13− ?? process.env.VERCEL_PROJECT_PRODUCTION_URL
14− ?? process.env.VERCEL_URL
15− ?? "";
16−
17− if (!configured.trim()) {
18− return null;
19− }
20−
21− try {
22− const normalized =
23− configured.startsWith("http://") || configured.startsWith("https://")
24− ? configured
25− : `https://${configured}`;
26−
27− return new URL(normalized).origin;
28− } catch {
29− return null;
30− }
31−};
32−
3311 export const getExternalOrigin = (request: Request): string => {
34− const configured = configuredExternalOrigin();
12+ const configured = configuredExternalOriginFromEnv();
3513 if (configured) {
3614 return configured;
3715 }
packages/persistence-sql/src/sql-internals.ts+0−10
@@ -80,16 +80,6 @@ const trim = (value: string | undefined): string | undefined => { · 79 unmodified lines
8080 };
8181
8282 const resolvePostgresMaxConnections = (): number => {
83− const configured = process.env.CONTROL_PLANE_POSTGRES_MAX_CONNECTIONS
84− ?? process.env.POSTGRES_MAX_CONNECTIONS;
85−
86− if (configured) {
87− const parsed = Number.parseInt(configured, 10);
88− if (Number.isFinite(parsed) && parsed > 0) {
89− return parsed;
90− }
91− }
92−
9383 return process.env.NODE_ENV === "production" ? 1 : 10;
9484 };
9585