History

Fix execute-path web/runtime regressions and add GitHub source

Rhys Sullivan committed 7 months ago

Commit 2cc6c8b1 parent d03db829 files · +106 −13Browse files

Unified · Split

9 files
  1. .executor/executor.jsonc +13 −0
  2. apps/web/src/components/shell.tsx +9 −2
  3. apps/web/src/views/source-detail.tsx +44 −4
  4. bun.lock +0 −2
  5. packages/clients/react/src/index.ts +3 −1
  6. packages/platform/sdk/package.json +0 −2
  7. packages/platform/sdk/src/runtime/control-plane-runtime.test.ts +1 −1
  8. packages/platform/sdk/src/runtime/execution/test-http-client.ts +1 −1
  9. packages/platform/server/src/index.ts +35 −0
.executor/executor.jsonc+13−0
@@ -1,4 +1,17 @@
1{1{
2 "sources": {
3 "github": {
4 "kind": "openapi",
5 "name": "GitHub",
6 "connection": {
7 "endpoint": "https://api.github.com/"
8 },
9 "binding": {
10 "specUrl": "https://raw.githubusercontent.com/github/rest-api-description/main/descriptions/api.github.com/api.github.com.json",
11 "defaultHeaders": null
12 }
13 }
14 },
2 "policies": {15 "policies": {
3 "demo.*": {16 "demo.*": {
4 "match": "demo.*",17 "match": "demo.*",
apps/web/src/components/shell.tsx+9−2
@@ -27,6 +27,8 @@ const { VITE_APP_VERSION, VITE_GITHUB_URL } = (import.meta as ImportMeta & { · 26 unmodified lines
27 27
28type UpdateChannel = "latest" | "beta";28type UpdateChannel = "latest" | "beta";
29 29
30const EXECUTOR_DIST_TAGS_PATH = "/v1/app/npm/dist-tags";
31
30type ParsedVersion = {32type ParsedVersion = {
31 readonly major: number;33 readonly major: number;
32 readonly minor: number;34 readonly minor: number;
@@ -139,8 +141,13 @@ function useLatestVersion(currentVersion: string) { · 106 unmodified lines
139 141
140 useEffect(() => {142 useEffect(() => {
141 let cancelled = false;143 let cancelled = false;
142 fetch("https://registry.npmjs.org/-/package/executor/dist-tags")144 fetch(EXECUTOR_DIST_TAGS_PATH)
143 .then((res) => res.json())145 .then(async (res) => {
146 if (!res.ok) {
147 throw new Error(`Failed to load dist tags: ${res.status}`);
148 }
149 return res.json() as Promise<Partial<Record<UpdateChannel, string>>>;
150 })
144 .then((data: Partial<Record<UpdateChannel, string>>) => {151 .then((data: Partial<Record<UpdateChannel, string>>) => {
145 if (!cancelled) {152 if (!cancelled) {
146 setLatestVersion(data[channel] ?? null);153 setLatestVersion(data[channel] ?? null);
apps/web/src/views/source-detail.tsx+44−4
@@ -122,12 +122,50 @@ const readBindingTransport = (source: Source): "auto" | "streamable-http" | "sse · 121 unmodified lines
122 : undefined;122 : undefined;
123};123};
124 124
125type RefreshableHttpAuth =
126 | { kind: "none" }
127 | {
128 kind: "bearer";
129 headerName?: string | null;
130 prefix?: string | null;
131 token?: string | null;
132 tokenRef?: { providerId: string; handle: string } | null;
133 }
134 | {
135 kind: "oauth2";
136 headerName?: string | null;
137 prefix?: string | null;
138 accessToken?: string | null;
139 accessTokenRef?: { providerId: string; handle: string } | null;
140 refreshToken?: string | null;
141 refreshTokenRef?: { providerId: string; handle: string } | null;
142 };
143
125const refreshableHttpAuth = (144const refreshableHttpAuth = (
126 auth: Source["auth"],145 auth: Source["auth"],
127): Extract<Source["auth"], { kind: "none" | "bearer" | "oauth2" }> | undefined =>146): RefreshableHttpAuth | undefined => {
128 auth.kind === "none" || auth.kind === "bearer" || auth.kind === "oauth2"147 switch (auth.kind) {
129 ? auth148 case "none":
130 : undefined;149 return { kind: "none" };
150 case "bearer":
151 return {
152 kind: "bearer",
153 headerName: auth.headerName,
154 prefix: auth.prefix,
155 tokenRef: auth.token,
156 };
157 case "oauth2":
158 return {
159 kind: "oauth2",
160 headerName: auth.headerName,
161 prefix: auth.prefix,
162 accessTokenRef: auth.accessToken,
163 refreshTokenRef: auth.refreshToken,
164 };
165 default:
166 return undefined;
167 }
168};
131 169
132const refreshPayloadFromSource = (source: Source): ConnectSourcePayload | null => {170const refreshPayloadFromSource = (source: Source): ConnectSourcePayload | null => {
133 switch (source.kind) {171 switch (source.kind) {
@@ -193,6 +231,8 @@ const refreshPayloadFromSource = (source: Source): ConnectSourcePayload | null = · 59 unmodified lines
193 auth: refreshableHttpAuth(source.auth),231 auth: refreshableHttpAuth(source.auth),
194 };232 };
195 }233 }
234 default:
235 return null;
196 }236 }
197};237};
198 238
bun.lock+0−2
@@ -325,8 +325,6 @@ · 324 unmodified lines
325 },325 },
326 "devDependencies": {326 "devDependencies": {
327 "@effect/vitest": "catalog:",327 "@effect/vitest": "catalog:",
328 "@executor/platform-api": "workspace:*",
329 "@executor/platform-internal": "workspace:*",
330 "@modelcontextprotocol/sdk": "^1.26.0",328 "@modelcontextprotocol/sdk": "^1.26.0",
331 "@types/node": "catalog:",329 "@types/node": "catalog:",
332 "bun-types": "catalog:",330 "bun-types": "catalog:",
packages/clients/react/src/index.ts+3−1
@@ -3,12 +3,14 @@ import type * as Registry from "@effect-atom/atom/Registry"; · 2 unmodified lines
3import { RegistryContext, RegistryProvider, useAtomValue } from "@effect-atom/atom-react";3import { RegistryContext, RegistryProvider, useAtomValue } from "@effect-atom/atom-react";
4import {4import {
5 createControlPlaneClient,5 createControlPlaneClient,
6 type ControlPlaneClient,
7} from "@executor/platform-api/client";
8import {
6 type CompleteSourceOAuthResult,9 type CompleteSourceOAuthResult,
7 type ConnectSourceBatchPayload,10 type ConnectSourceBatchPayload,
8 type ConnectSourceBatchResult,11 type ConnectSourceBatchResult,
9 type ConnectSourcePayload,12 type ConnectSourcePayload,
10 type ConnectSourceResult,13 type ConnectSourceResult,
11 type ControlPlaneClient,
12 type CreateSecretPayload,14 type CreateSecretPayload,
13 type CreateSecretResult,15 type CreateSecretResult,
14 type CreateSourcePayload,16 type CreateSourcePayload,
packages/platform/sdk/package.json+0−2
@@ -49,8 +49,6 @@ · 48 unmodified lines
49 },49 },
50 "devDependencies": {50 "devDependencies": {
51 "@effect/vitest": "catalog:",51 "@effect/vitest": "catalog:",
52 "@executor/platform-api": "workspace:*",
53 "@executor/platform-internal": "workspace:*",
54 "@modelcontextprotocol/sdk": "^1.26.0",52 "@modelcontextprotocol/sdk": "^1.26.0",
55 "@types/node": "catalog:",53 "@types/node": "catalog:",
56 "bun-types": "catalog:",54 "bun-types": "catalog:",
packages/platform/sdk/src/runtime/control-plane-runtime.test.ts+1−1
@@ -23,7 +23,7 @@ import { · 22 unmodified lines
23import type { ToolPath } from "@executor/codemode-core";23import type { ToolPath } from "@executor/codemode-core";
24import { createCatalogImportMetadata } from "@executor/source-core";24import { createCatalogImportMetadata } from "@executor/source-core";
25import { createGraphqlCatalogFragment } from "@executor/source-graphql";25import { createGraphqlCatalogFragment } from "@executor/source-graphql";
26import { createExecutorAdminToolMap } from "@executor/platform-internal";26import { createExecutorAdminToolMap } from "../../../internal/src/index";
27 27
28import {28import {
29 type ControlPlaneRuntime,29 type ControlPlaneRuntime,
packages/platform/sdk/src/runtime/execution/test-http-client.ts+1−1
@@ -6,7 +6,7 @@ import { NodeHttpServer } from "@effect/platform-node"; · 5 unmodified lines
6import {6import {
7 ControlPlaneApi,7 ControlPlaneApi,
8 createControlPlaneApiLayer,8 createControlPlaneApiLayer,
9} from "@executor/platform-api";9} from "../../../../api/src/index";
10import * as Effect from "effect/Effect";10import * as Effect from "effect/Effect";
11import * as Layer from "effect/Layer";11import * as Layer from "effect/Layer";
12 12
packages/platform/server/src/index.ts+35−0
@@ -98,6 +98,10 @@ export type LocalExecutorRequestHandler = { · 97 unmodified lines
98type ControlPlaneWebHandler = ReturnType<typeof HttpApiBuilder.toWebHandler>;98type ControlPlaneWebHandler = ReturnType<typeof HttpApiBuilder.toWebHandler>;
99type ExecutorMcpHandler = ReturnType<typeof createExecutorMcpRequestHandler>;99type ExecutorMcpHandler = ReturnType<typeof createExecutorMcpRequestHandler>;
100 100
101const EXECUTOR_NPM_DIST_TAGS_PATHNAME = "/v1/app/npm/dist-tags";
102const EXECUTOR_NPM_DIST_TAGS_URL =
103 "https://registry.npmjs.org/-/package/executor/dist-tags";
104
101const disposeRuntime = (runtime: ControlPlaneRuntime) =>105const disposeRuntime = (runtime: ControlPlaneRuntime) =>
102 Effect.tryPromise({106 Effect.tryPromise({
103 try: () => runtime.close(),107 try: () => runtime.close(),
@@ -306,6 +310,34 @@ const isApiRequest = (request: Request): boolean => { · 202 unmodified lines
306 return pathname === "/mcp" || pathname === "/v1" || pathname.startsWith("/v1/");310 return pathname === "/mcp" || pathname === "/v1" || pathname.startsWith("/v1/");
307};311};
308 312
313const handleExecutorNpmDistTagsRequest = async (): Promise<Response> => {
314 try {
315 const upstream = await fetch(EXECUTOR_NPM_DIST_TAGS_URL, {
316 headers: {
317 accept: "application/json",
318 },
319 });
320 const body = upstream.ok ? await upstream.text() : "{}";
321 return new Response(body, {
322 status: upstream.ok ? 200 : 502,
323 headers: {
324 "cache-control": upstream.ok
325 ? upstream.headers.get("cache-control") ?? "public, max-age=300"
326 : "no-store",
327 "content-type": "application/json; charset=utf-8",
328 },
329 });
330 } catch {
331 return new Response("{}", {
332 status: 502,
333 headers: {
334 "cache-control": "no-store",
335 "content-type": "application/json; charset=utf-8",
336 },
337 });
338 }
339};
340
309export const createLocalExecutorRequestHandler = (341export const createLocalExecutorRequestHandler = (
310 options: StartLocalExecutorServerOptions = {},342 options: StartLocalExecutorServerOptions = {},
311): Effect.Effect<LocalExecutorRequestHandler, Error, Scope.Scope> =>343): Effect.Effect<LocalExecutorRequestHandler, Error, Scope.Scope> =>
@@ -359,6 +391,9 @@ export const createLocalExecutorRequestHandler = ( · 47 unmodified lines
359 runtime,391 runtime,
360 handleApiRequest: (request) => {392 handleApiRequest: (request) => {
361 const pathname = new URL(request.url).pathname;393 const pathname = new URL(request.url).pathname;
394 if (pathname === EXECUTOR_NPM_DIST_TAGS_PATHNAME) {
395 return handleExecutorNpmDistTagsRequest();
396 }
362 return pathname === "/mcp"397 return pathname === "/mcp"
363 ? mcpHandler.handleRequest(request)398 ? mcpHandler.handleRequest(request)
364 : apiHandler.handler(request);399 : apiHandler.handler(request);