Unified · Split
| @@ -40,6 +40,7 @@ · 39 unmodified lines | |||
| 40 | "@executor/platform-api": "workspace:*", | 40 | "@executor/platform-api": "workspace:*", |
| 41 | "@executor/platform-internal": "workspace:*", | 41 | "@executor/platform-internal": "workspace:*", |
| 42 | "@executor/platform-sdk": "workspace:*", | 42 | "@executor/platform-sdk": "workspace:*", |
| 43 | "@executor/platform-sdk-file": "workspace:*", | ||
| 43 | "@executor/server": "workspace:*", | 44 | "@executor/server": "workspace:*", |
| 44 | "effect": "catalog:" | 45 | "effect": "catalog:" |
| 45 | }, | 46 | }, |
| @@ -13,13 +13,16 @@ import { · 12 unmodified lines | |||
| 13 | createControlPlaneClient, | 13 | createControlPlaneClient, |
| 14 | type ControlPlaneClient, | 14 | type ControlPlaneClient, |
| 15 | } from "@executor/platform-api"; | 15 | } from "@executor/platform-api"; |
| 16 | import { createExecutorAdminToolMap } from "@executor/platform-internal"; | 16 | import { createWorkspaceExecutorAdminToolMap } from "@executor/platform-internal"; |
| 17 | import { | 17 | import { |
| 18 | EXECUTOR_SOURCES_ADD_HELP_LINES, | 18 | EXECUTOR_SOURCES_ADD_HELP_LINES, |
| 19 | RuntimeExecutionResolverService, | 19 | RuntimeExecutionResolverService, |
| 20 | createControlPlaneRuntime, | ||
| 21 | type ControlPlaneRuntime, | ||
| 22 | } from "@executor/platform-sdk/runtime"; | 20 | } from "@executor/platform-sdk/runtime"; |
| 21 | import { | ||
| 22 | createExecutorEffect, | ||
| 23 | type Executor, | ||
| 24 | } from "@executor/platform-sdk"; | ||
| 25 | import { createLocalExecutorBackend } from "@executor/platform-sdk-file"; | ||
| 23 | import { | 26 | import { |
| 24 | ExecutionIdSchema, | 27 | ExecutionIdSchema, |
| 25 | type ExecutionEnvelope, | 28 | type ExecutionEnvelope, |
| @@ -248,9 +251,9 @@ const formatCatalogUnavailableMessage = (cause: Cause.Cause<unknown>): string => · 222 unmodified lines | |||
| 248 | : `Current workspace catalog unavailable: ${message}`; | 251 | : `Current workspace catalog unavailable: ${message}`; |
| 249 | }; | 252 | }; |
| 250 | 253 | ||
| 251 | const closeRuntime = (runtime: ControlPlaneRuntime) => | 254 | const closeExecutor = (executor: Executor) => |
| 252 | Effect.tryPromise({ | 255 | Effect.tryPromise({ |
| 253 | try: () => runtime.close(), | 256 | try: () => executor.close(), |
| 254 | catch: toError, | 257 | catch: toError, |
| 255 | }).pipe(Effect.catchAll(() => Effect.void)); | 258 | }).pipe(Effect.catchAll(() => Effect.void)); |
| 256 | 259 | ||
| @@ -275,27 +278,29 @@ const buildRunWorkflowText = ( · 18 unmodified lines | |||
| 275 | 278 | ||
| 276 | const loadRunWorkflowText = (): Effect.Effect<string, Error, never> => | 279 | const loadRunWorkflowText = (): Effect.Effect<string, Error, never> => |
| 277 | Effect.acquireUseRelease( | 280 | Effect.acquireUseRelease( |
| 278 | createControlPlaneRuntime({ | 281 | createExecutorEffect({ |
| 279 | localDataDir: DEFAULT_LOCAL_DATA_DIR, | 282 | backend: createLocalExecutorBackend({ |
| 280 | createInternalToolMap: createExecutorAdminToolMap, | 283 | localDataDir: DEFAULT_LOCAL_DATA_DIR, |
| 284 | }), | ||
| 285 | createInternalToolMap: createWorkspaceExecutorAdminToolMap, | ||
| 281 | }).pipe(Effect.mapError(toError)), | 286 | }).pipe(Effect.mapError(toError)), |
| 282 | (runtime) => | 287 | (executor) => |
| 283 | Effect.gen(function* () { | 288 | Effect.gen(function* () { |
| 284 | const environment = yield* Effect.gen(function* () { | 289 | const environment = yield* Effect.gen(function* () { |
| 285 | const resolveExecutionEnvironment = yield* RuntimeExecutionResolverService; | 290 | const resolveExecutionEnvironment = yield* RuntimeExecutionResolverService; |
| 286 | return yield* resolveExecutionEnvironment({ | 291 | return yield* resolveExecutionEnvironment({ |
| 287 | workspaceId: runtime.localInstallation.workspaceId, | 292 | workspaceId: executor.workspaceId, |
| 288 | accountId: runtime.localInstallation.accountId, | 293 | accountId: executor.accountId, |
| 289 | executionId: ExecutionIdSchema.make("exec_help"), | 294 | executionId: ExecutionIdSchema.make("exec_help"), |
| 290 | }); | 295 | }); |
| 291 | }).pipe( | 296 | }).pipe( |
| 292 | Effect.provide(runtime.runtimeLayer), | 297 | Effect.provide(executor.runtime.runtimeLayer), |
| 293 | Effect.mapError(toError), | 298 | Effect.mapError(toError), |
| 294 | ); | 299 | ); |
| 295 | 300 | ||
| 296 | return yield* buildRunWorkflowText(environment.catalog); | 301 | return yield* buildRunWorkflowText(environment.catalog); |
| 297 | }), | 302 | }), |
| 298 | closeRuntime, | 303 | closeExecutor, |
| 299 | ).pipe( | 304 | ).pipe( |
| 300 | Effect.catchAllCause((cause) => | 305 | Effect.catchAllCause((cause) => |
| 301 | Effect.succeed( | 306 | Effect.succeed( |
| @@ -24,6 +24,7 @@ · 23 unmodified lines | |||
| 24 | "@effect/platform": "catalog:", | 24 | "@effect/platform": "catalog:", |
| 25 | "@effect/platform-node": "catalog:", | 25 | "@effect/platform-node": "catalog:", |
| 26 | "@effect/vitest": "catalog:", | 26 | "@effect/vitest": "catalog:", |
| 27 | "@executor/platform-sdk-file": "workspace:*", | ||
| 27 | "@types/jsdom": "^21.1.7", | 28 | "@types/jsdom": "^21.1.7", |
| 28 | "@types/node": "catalog:", | 29 | "@types/node": "catalog:", |
| 29 | "@types/react": "^19.2.10", | 30 | "@types/react": "^19.2.10", |
| @@ -6,10 +6,9 @@ import { describe, expect, it } from "@effect/vitest"; · 5 unmodified lines | |||
| 6 | import { | 6 | import { |
| 7 | createControlPlaneApiLayer, | 7 | createControlPlaneApiLayer, |
| 8 | } from "@executor/platform-api"; | 8 | } from "@executor/platform-api"; |
| 9 | import { | 9 | import { createExecutorEffect } from "@executor/platform-sdk"; |
| 10 | createControlPlaneRuntime, | 10 | import type { ControlPlaneRuntime } from "@executor/platform-sdk/runtime"; |
| 11 | type ControlPlaneRuntime, | 11 | import { createLocalControlPlaneRuntime as createControlPlaneRuntime } from "@executor/platform-sdk-file"; |
| 12 | } from "@executor/platform-sdk/runtime"; | ||
| 13 | import type { | 12 | import type { |
| 14 | LocalInstallation, | 13 | LocalInstallation, |
| 15 | Source, | 14 | Source, |
| @@ -110,8 +109,15 @@ const startControlPlaneServer = async (): Promise<ApiServer> => { · 94 unmodified lines | |||
| 110 | const scope = await Effect.runPromise(Scope.make()); | 109 | const scope = await Effect.runPromise(Scope.make()); |
| 111 | 110 | ||
| 112 | try { | 111 | try { |
| 112 | const executor = await Effect.runPromise( | ||
| 113 | createExecutorEffect({ | ||
| 114 | backend: { | ||
| 115 | createRuntime: () => Effect.succeed(runtime), | ||
| 116 | }, | ||
| 117 | }), | ||
| 118 | ); | ||
| 113 | const serverLayer = HttpApiBuilder.serve().pipe( | 119 | const serverLayer = HttpApiBuilder.serve().pipe( |
| 114 | Layer.provide(createControlPlaneApiLayer(runtime.runtimeLayer)), | 120 | Layer.provide(createControlPlaneApiLayer(executor)), |
| 115 | Layer.provideMerge(NodeHttpServer.layerTest), | 121 | Layer.provideMerge(NodeHttpServer.layerTest), |
| 116 | ); | 122 | ); |
| 117 | const context = await Effect.runPromise(Layer.buildWithScope(serverLayer, scope)); | 123 | const context = await Effect.runPromise(Layer.buildWithScope(serverLayer, scope)); |
| @@ -2,11 +2,11 @@ import { HttpApiEndpoint, HttpApiGroup, HttpApiSchema } from "@effect/platform"; · 1 unmodified line | |||
| 2 | import { | 2 | import { |
| 3 | CreateExecutionPayloadSchema, | 3 | CreateExecutionPayloadSchema, |
| 4 | ResumeExecutionPayloadSchema, | 4 | ResumeExecutionPayloadSchema, |
| 5 | } from "@executor/platform-sdk/executions/contracts"; | 5 | } from "@executor/platform-sdk/contracts"; |
| 6 | export type { | 6 | export type { |
| 7 | CreateExecutionPayload, | 7 | CreateExecutionPayload, |
| 8 | ResumeExecutionPayload, | 8 | ResumeExecutionPayload, |
| 9 | } from "@executor/platform-sdk/executions/contracts"; | 9 | } from "@executor/platform-sdk/contracts"; |
| 10 | import { | 10 | import { |
| 11 | ExecutionIdSchema, | 11 | ExecutionIdSchema, |
| 12 | ExecutionEnvelopeSchema, | 12 | ExecutionEnvelopeSchema, |
| @@ -1,10 +1,5 @@ | |||
| 1 | import { HttpApiBuilder } from "@effect/platform"; | 1 | import { HttpApiBuilder } from "@effect/platform"; |
| 2 | import * as Effect from "effect/Effect"; | 2 | import * as Effect from "effect/Effect"; |
| 3 | import { | ||
| 4 | createExecution, | ||
| 5 | getExecution, | ||
| 6 | resumeExecution, | ||
| 7 | } from "@executor/platform-sdk/runtime"; | ||
| 8 | 3 | ||
| 9 | import { ControlPlaneApi } from "../api"; | 4 | import { ControlPlaneApi } from "../api"; |
| 10 | import { resolveRequestedLocalWorkspace } from "../local-context"; | 5 | import { resolveRequestedLocalWorkspace } from "../local-context"; |
| @@ -16,34 +11,18 @@ export const ControlPlaneExecutionsLive = HttpApiBuilder.group( · 5 unmodified lines | |||
| 16 | handlers | 11 | handlers |
| 17 | .handle("create", ({ path, payload }) => | 12 | .handle("create", ({ path, payload }) => |
| 18 | resolveRequestedLocalWorkspace("executions.create", path.workspaceId).pipe( | 13 | resolveRequestedLocalWorkspace("executions.create", path.workspaceId).pipe( |
| 19 | Effect.flatMap((runtimeLocalWorkspace) => | 14 | Effect.flatMap((executor) => executor.effect.executions.create(payload)), |
| 20 | createExecution({ | ||
| 21 | workspaceId: path.workspaceId, | ||
| 22 | payload, | ||
| 23 | createdByAccountId: runtimeLocalWorkspace.installation.accountId, | ||
| 24 | }) | ||
| 25 | ), | ||
| 26 | ), | 15 | ), |
| 27 | ) | 16 | ) |
| 28 | .handle("get", ({ path }) => | 17 | .handle("get", ({ path }) => |
| 29 | resolveRequestedLocalWorkspace("executions.get", path.workspaceId).pipe( | 18 | resolveRequestedLocalWorkspace("executions.get", path.workspaceId).pipe( |
| 30 | Effect.zipRight( | 19 | Effect.flatMap((executor) => executor.effect.executions.get(path.executionId)), |
| 31 | getExecution({ | ||
| 32 | workspaceId: path.workspaceId, | ||
| 33 | executionId: path.executionId, | ||
| 34 | }), | ||
| 35 | ), | ||
| 36 | ), | 20 | ), |
| 37 | ) | 21 | ) |
| 38 | .handle("resume", ({ path, payload }) => | 22 | .handle("resume", ({ path, payload }) => |
| 39 | resolveRequestedLocalWorkspace("executions.resume", path.workspaceId).pipe( | 23 | resolveRequestedLocalWorkspace("executions.resume", path.workspaceId).pipe( |
| 40 | Effect.flatMap((runtimeLocalWorkspace) => | 24 | Effect.flatMap((executor) => |
| 41 | resumeExecution({ | 25 | executor.effect.executions.resume(path.executionId, payload) |
| 42 | workspaceId: path.workspaceId, | ||
| 43 | executionId: path.executionId, | ||
| 44 | payload, | ||
| 45 | resumedByAccountId: runtimeLocalWorkspace.installation.accountId, | ||
| 46 | }) | ||
| 47 | ), | 26 | ), |
| 48 | ), | 27 | ), |
| 49 | ), | 28 | ), |
| @@ -0,0 +1,35 @@ | |||
| 1 | import type { Executor } from "@executor/platform-sdk"; | ||
| 2 | import type { WorkspaceId } from "@executor/platform-sdk/schema"; | ||
| 3 | import { | ||
| 4 | ControlPlaneBadRequestError, | ||
| 5 | ControlPlaneForbiddenError, | ||
| 6 | ControlPlaneUnauthorizedError, | ||
| 7 | } from "@executor/platform-sdk/errors"; | ||
| 8 | import * as Context from "effect/Context"; | ||
| 9 | import * as Effect from "effect/Effect"; | ||
| 10 | import * as Layer from "effect/Layer"; | ||
| 11 | |||
| 12 | export class ControlPlaneExecutor extends Context.Tag( | ||
| 13 | "@executor/platform-api/ControlPlaneExecutor", | ||
| 14 | )<ControlPlaneExecutor, Executor>() {} | ||
| 15 | |||
| 16 | export const createControlPlaneExecutorLayer = (executor: Executor) => | ||
| 17 | Layer.succeed(ControlPlaneExecutor, executor); | ||
| 18 | |||
| 19 | export const getControlPlaneExecutor = () => ControlPlaneExecutor; | ||
| 20 | |||
| 21 | export const resolveRequestedLocalWorkspace = ( | ||
| 22 | operation: string, | ||
| 23 | workspaceId: WorkspaceId, | ||
| 24 | ) => | ||
| 25 | Effect.flatMap(ControlPlaneExecutor, (executor) => | ||
| 26 | executor.workspaceId === workspaceId | ||
| 27 | ? Effect.succeed(executor) | ||
| 28 | : Effect.fail( | ||
| 29 | new ControlPlaneForbiddenError({ | ||
| 30 | operation, | ||
| 31 | message: "Requested workspace is not the active local workspace", | ||
| 32 | details: `requestedWorkspaceId=${workspaceId} activeWorkspaceId=${executor.workspaceId}`, | ||
| 33 | }), | ||
| 34 | ), | ||
| 35 | ); | ||
| @@ -1,7 +1,9 @@ | |||
| 1 | import { HttpApiBuilder } from "@effect/platform"; | 1 | import { HttpApiBuilder } from "@effect/platform"; |
| 2 | import * as Layer from "effect/Layer"; | 2 | import * as Layer from "effect/Layer"; |
| 3 | import type { Executor } from "@executor/platform-sdk"; | ||
| 3 | 4 | ||
| 4 | import { ControlPlaneApi } from "./api"; | 5 | import { ControlPlaneApi } from "./api"; |
| 6 | import { createControlPlaneExecutorLayer } from "./executor-context"; | ||
| 5 | import { ControlPlaneExecutionsLive } from "./executions/http"; | 7 | import { ControlPlaneExecutionsLive } from "./executions/http"; |
| 6 | import { ControlPlaneLocalLive } from "./local/http"; | 8 | import { ControlPlaneLocalLive } from "./local/http"; |
| 7 | import { ControlPlaneOAuthLive } from "./oauth/http"; | 9 | import { ControlPlaneOAuthLive } from "./oauth/http"; |
| @@ -18,15 +20,14 @@ export const ControlPlaneApiLive = HttpApiBuilder.api(ControlPlaneApi).pipe( · 10 unmodified lines | |||
| 18 | 20 | ||
| 19 | export type ControlPlaneApiRuntimeContext = Layer.Layer.Context<typeof ControlPlaneApiLive>; | 21 | export type ControlPlaneApiRuntimeContext = Layer.Layer.Context<typeof ControlPlaneApiLive>; |
| 20 | 22 | ||
| 21 | export type BuiltControlPlaneApiLayer = Layer.Layer< | 23 | export const createControlPlaneApiLayer = (executor: Executor) => |
| 22 | Layer.Layer.Success<typeof ControlPlaneApiLive>, | ||
| 23 | Layer.Layer.Error<typeof ControlPlaneApiLive>, | ||
| 24 | never | ||
| 25 | >; | ||
| 26 | |||
| 27 | export const createControlPlaneApiLayer = <ERuntime>( | ||
| 28 | runtimeLayer: Layer.Layer<ControlPlaneApiRuntimeContext, ERuntime, never>, | ||
| 29 | ) => | ||
| 30 | ControlPlaneApiLive.pipe( | 24 | ControlPlaneApiLive.pipe( |
| 31 | Layer.provide(runtimeLayer), | 25 | Layer.provide(createControlPlaneExecutorLayer(executor)), |
| 32 | ); | 26 | ); |
| 27 | |||
| 28 | export type BuiltControlPlaneApiLayer = ReturnType< | ||
| 29 | typeof createControlPlaneApiLayer | ||
| 30 | >; | ||
| 31 | |||
| 32 | export const createExecutorApiLayer = (executor: Executor) => | ||
| 33 | createControlPlaneApiLayer(executor); | ||
| @@ -22,6 +22,7 @@ export { · 21 unmodified lines | |||
| 22 | type ControlPlaneApiRuntimeContext, | 22 | type ControlPlaneApiRuntimeContext, |
| 23 | type BuiltControlPlaneApiLayer, | 23 | type BuiltControlPlaneApiLayer, |
| 24 | createControlPlaneApiLayer, | 24 | createControlPlaneApiLayer, |
| 25 | createExecutorApiLayer, | ||
| 25 | } from "./http"; | 26 | } from "./http"; |
| 26 | 27 | ||
| 27 | export { | 28 | export { |
| @@ -1,25 +1,6 @@ | |||
| 1 | import type { WorkspaceId } from "@executor/platform-sdk/schema"; | 1 | export { |
| 2 | import * as Effect from "effect/Effect"; | 2 | createControlPlaneExecutorLayer, |
| 3 | 3 | getControlPlaneExecutor, | |
| 4 | import { | 4 | resolveRequestedLocalWorkspace, |
| 5 | RuntimeLocalWorkspaceMismatchError, | 5 | type ControlPlaneExecutor, |
| 6 | requireRuntimeLocalWorkspace, | 6 | } from "./executor-context"; |
| 7 | } from "@executor/platform-sdk/runtime"; | ||
| 8 | import { ControlPlaneForbiddenError } from "./errors"; | ||
| 9 | |||
| 10 | export const resolveRequestedLocalWorkspace = ( | ||
| 11 | operation: string, | ||
| 12 | workspaceId: WorkspaceId, | ||
| 13 | ) => | ||
| 14 | requireRuntimeLocalWorkspace(workspaceId).pipe( | ||
| 15 | Effect.mapError((cause) => | ||
| 16 | new ControlPlaneForbiddenError({ | ||
| 17 | operation, | ||
| 18 | message: "Requested workspace is not the active local workspace", | ||
| 19 | details: | ||
| 20 | cause instanceof RuntimeLocalWorkspaceMismatchError | ||
| 21 | ? `requestedWorkspaceId=${cause.requestedWorkspaceId} activeWorkspaceId=${cause.activeWorkspaceId}` | ||
| 22 | : "Runtime local workspace is unavailable", | ||
| 23 | }) | ||
| 24 | ), | ||
| 25 | ); | ||
| @@ -7,7 +7,7 @@ import { · 6 unmodified lines | |||
| 7 | SecretListItemSchema, | 7 | SecretListItemSchema, |
| 8 | UpdateSecretPayloadSchema, | 8 | UpdateSecretPayloadSchema, |
| 9 | UpdateSecretResultSchema, | 9 | UpdateSecretResultSchema, |
| 10 | } from "@executor/platform-sdk/local/contracts"; | 10 | } from "@executor/platform-sdk/contracts"; |
| 11 | import { | 11 | import { |
| 12 | ControlPlaneBadRequestError, | 12 | ControlPlaneBadRequestError, |
| 13 | ControlPlaneNotFoundError, | 13 | ControlPlaneNotFoundError, |
| @@ -26,7 +26,7 @@ export type { · 12 unmodified lines | |||
| 26 | SecretProvider, | 26 | SecretProvider, |
| 27 | UpdateSecretPayload, | 27 | UpdateSecretPayload, |
| 28 | UpdateSecretResult, | 28 | UpdateSecretResult, |
| 29 | } from "@executor/platform-sdk/local/contracts"; | 29 | } from "@executor/platform-sdk/contracts"; |
| 30 | 30 | ||
| 31 | export class LocalApi extends HttpApiGroup.make("local") | 31 | export class LocalApi extends HttpApiGroup.make("local") |
| 32 | .add( | 32 | .add( |
| @@ -38,7 +38,8 @@ export class LocalApi extends HttpApiGroup.make("local") · 5 unmodified lines | |||
| 38 | ) | 38 | ) |
| 39 | .add( | 39 | .add( |
| 40 | HttpApiEndpoint.get("config")`/local/config` | 40 | HttpApiEndpoint.get("config")`/local/config` |
| 41 | .addSuccess(InstanceConfigSchema), | 41 | .addSuccess(InstanceConfigSchema) |
| 42 | .addError(ControlPlaneStorageError), | ||
| 42 | ) | 43 | ) |
| 43 | .add( | 44 | .add( |
| 44 | HttpApiEndpoint.get("listSecrets")`/local/secrets` | 45 | HttpApiEndpoint.get("listSecrets")`/local/secrets` |
| @@ -1,29 +1,63 @@ | |||
| 1 | import { HttpApiBuilder } from "@effect/platform"; | 1 | import { HttpApiBuilder } from "@effect/platform"; |
| 2 | import { | 2 | import * as Effect from "effect/Effect"; |
| 3 | createLocalSecret, | ||
| 4 | deleteLocalSecret, | ||
| 5 | getLocalInstanceConfig, | ||
| 6 | getLocalInstallation, | ||
| 7 | listLocalSecrets, | ||
| 8 | updateLocalSecret, | ||
| 9 | } from "@executor/platform-sdk"; | ||
| 10 | 3 | ||
| 11 | import { ControlPlaneApi } from "../api"; | 4 | import { ControlPlaneApi } from "../api"; |
| 5 | import { ControlPlaneStorageError } from "../errors"; | ||
| 6 | import { getControlPlaneExecutor } from "../executor-context"; | ||
| 7 | |||
| 8 | const toStorageError = (operation: string) => (cause: unknown) => | ||
| 9 | new ControlPlaneStorageError({ | ||
| 10 | operation, | ||
| 11 | message: cause instanceof Error ? cause.message : String(cause), | ||
| 12 | details: cause instanceof Error ? cause.stack ?? cause.message : String(cause), | ||
| 13 | }); | ||
| 12 | 14 | ||
| 13 | export const ControlPlaneLocalLive = HttpApiBuilder.group( | 15 | export const ControlPlaneLocalLive = HttpApiBuilder.group( |
| 14 | ControlPlaneApi, | 16 | ControlPlaneApi, |
| 15 | "local", | 17 | "local", |
| 16 | (handlers) => | 18 | (handlers) => |
| 17 | handlers | 19 | handlers |
| 18 | .handle("installation", () => getLocalInstallation()) | 20 | .handle("installation", () => |
| 19 | .handle("config", () => getLocalInstanceConfig()) | 21 | Effect.flatMap(getControlPlaneExecutor(), (executor) => |
| 20 | .handle("listSecrets", () => listLocalSecrets()) | 22 | executor.effect.local.installation().pipe( |
| 21 | .handle("createSecret", ({ payload }) => createLocalSecret(payload)) | 23 | Effect.mapError(toStorageError("local.installation")), |
| 24 | ) | ||
| 25 | ) | ||
| 26 | ) | ||
| 27 | .handle("config", () => | ||
| 28 | Effect.flatMap(getControlPlaneExecutor(), (executor) => | ||
| 29 | executor.effect.local.config().pipe( | ||
| 30 | Effect.mapError(toStorageError("local.config")), | ||
| 31 | ) | ||
| 32 | ) | ||
| 33 | ) | ||
| 34 | .handle("listSecrets", () => | ||
| 35 | Effect.flatMap(getControlPlaneExecutor(), (executor) => | ||
| 36 | executor.effect.secrets.list().pipe( | ||
| 37 | Effect.mapError(toStorageError("local.listSecrets")), | ||
| 38 | ) | ||
| 39 | ) | ||
| 40 | ) | ||
| 41 | .handle("createSecret", ({ payload }) => | ||
| 42 | Effect.flatMap(getControlPlaneExecutor(), (executor) => | ||
| 43 | executor.effect.secrets.create(payload).pipe( | ||
| 44 | Effect.mapError(toStorageError("local.createSecret")), | ||
| 45 | ) | ||
| 46 | ) | ||
| 47 | ) | ||
| 22 | .handle("updateSecret", ({ path, payload }) => | 48 | .handle("updateSecret", ({ path, payload }) => |
| 23 | updateLocalSecret({ | 49 | Effect.flatMap(getControlPlaneExecutor(), (executor) => |
| 24 | secretId: path.secretId, | 50 | executor.effect.secrets.update({ |
| 25 | payload, | 51 | secretId: path.secretId, |
| 26 | }), | 52 | payload, |
| 53 | }).pipe(Effect.mapError(toStorageError("local.updateSecret"))) | ||
| 54 | ) | ||
| 27 | ) | 55 | ) |
| 28 | .handle("deleteSecret", ({ path }) => deleteLocalSecret(path.secretId)), | 56 | .handle("deleteSecret", ({ path }) => |
| 57 | Effect.flatMap(getControlPlaneExecutor(), (executor) => | ||
| 58 | executor.effect.secrets.remove(path.secretId).pipe( | ||
| 59 | Effect.mapError(toStorageError("local.deleteSecret")), | ||
| 60 | ) | ||
| 61 | ) | ||
| 62 | ), | ||
| 29 | ); | 63 | ); |
| @@ -9,13 +9,15 @@ import * as Either from "effect/Either"; · 8 unmodified lines | |||
| 9 | import * as Effect from "effect/Effect"; | 9 | import * as Effect from "effect/Effect"; |
| 10 | import * as Schema from "effect/Schema"; | 10 | import * as Schema from "effect/Schema"; |
| 11 | 11 | ||
| 12 | import { RuntimeSourceAuthServiceTag } from "@executor/platform-sdk/runtime"; | ||
| 13 | import { ControlPlaneApi } from "../api"; | 12 | import { ControlPlaneApi } from "../api"; |
| 14 | import { | 13 | import { |
| 15 | ControlPlaneBadRequestError, | 14 | ControlPlaneBadRequestError, |
| 16 | ControlPlaneStorageError, | 15 | ControlPlaneStorageError, |
| 17 | } from "../errors"; | 16 | } from "../errors"; |
| 18 | import { resolveRequestedLocalWorkspace } from "../local-context"; | 17 | import { |
| 18 | getControlPlaneExecutor, | ||
| 19 | resolveRequestedLocalWorkspace, | ||
| 20 | } from "../local-context"; | ||
| 19 | import { | 21 | import { |
| 20 | SourceOAuthPopupResultSchema, | 22 | SourceOAuthPopupResultSchema, |
| 21 | type SourceOAuthPopupResult, | 23 | type SourceOAuthPopupResult, |
| @@ -236,23 +238,20 @@ export const ControlPlaneOAuthLive = HttpApiBuilder.group( · 214 unmodified lines | |||
| 236 | handlers | 238 | handlers |
| 237 | .handle("startSourceAuth", ({ path, payload }) => | 239 | .handle("startSourceAuth", ({ path, payload }) => |
| 238 | resolveRequestedLocalWorkspace("oauth.start_source_auth", path.workspaceId).pipe( | 240 | resolveRequestedLocalWorkspace("oauth.start_source_auth", path.workspaceId).pipe( |
| 239 | Effect.flatMap((runtimeLocalWorkspace) => | 241 | Effect.flatMap((executor) => |
| 240 | Effect.gen(function* () { | 242 | Effect.gen(function* () { |
| 241 | const request = yield* HttpServerRequest.HttpServerRequest; | 243 | const request = yield* HttpServerRequest.HttpServerRequest; |
| 242 | const sourceAuthService = yield* RuntimeSourceAuthServiceTag; | 244 | return yield* executor.effect.oauth.startSourceAuth({ |
| 243 | return yield* sourceAuthService.startSourceOAuthSession({ | 245 | baseUrl: resolveRequestOrigin(request), |
| 244 | workspaceId: path.workspaceId, | 246 | displayName: payload.name, |
| 245 | actorAccountId: runtimeLocalWorkspace.installation.accountId, | 247 | provider: { |
| 246 | baseUrl: resolveRequestOrigin(request), | 248 | kind: payload.provider, |
| 247 | displayName: payload.name, | 249 | endpoint: payload.endpoint, |
| 248 | provider: { | 250 | transport: payload.transport, |
| 249 | kind: payload.provider, | 251 | queryParams: payload.queryParams, |
| 250 | endpoint: payload.endpoint, | 252 | headers: payload.headers, |
| 251 | transport: payload.transport, | 253 | }, |
| 252 | queryParams: payload.queryParams, | 254 | }); |
| 253 | headers: payload.headers, | ||
| 254 | }, | ||
| 255 | }); | ||
| 256 | }).pipe( | 255 | }).pipe( |
| 257 | Effect.catchAllCause((cause) => | 256 | Effect.catchAllCause((cause) => |
| 258 | Effect.fail( | 257 | Effect.fail( |
| @@ -269,53 +268,54 @@ export const ControlPlaneOAuthLive = HttpApiBuilder.group( · 10 unmodified lines | |||
| 269 | ), | 268 | ), |
| 270 | ) | 269 | ) |
| 271 | .handle("sourceAuthCallback", ({ urlParams }) => | 270 | .handle("sourceAuthCallback", ({ urlParams }) => |
| 272 | Effect.gen(function* () { | 271 | Effect.flatMap(getControlPlaneExecutor(), (executor) => |
| 273 | const sourceAuthService = yield* RuntimeSourceAuthServiceTag; | 272 | Effect.gen(function* () { |
| 274 | const completed = yield* Effect.either( | 273 | const completed = yield* Effect.either( |
| 275 | sourceAuthService.completeSourceOAuthSession({ | 274 | executor.effect.oauth.completeSourceAuth({ |
| 276 | state: urlParams.state, | 275 | state: urlParams.state, |
| 277 | code: urlParams.code, | 276 | code: urlParams.code, |
| 278 | error: urlParams.error, | 277 | error: urlParams.error, |
| 279 | errorDescription: urlParams.error_description, | 278 | errorDescription: urlParams.error_description, |
| 280 | }), | 279 | }), |
| 281 | ); | 280 | ); |
| 281 | |||
| 282 | if (Either.isRight(completed)) { | ||
| 283 | return htmlResponse( | ||
| 284 | sourceOAuthPopupResultDocument({ | ||
| 285 | title: "OAuth connected", | ||
| 286 | message: "OAuth credentials are ready. Return to the source form to finish saving.", | ||
| 287 | status: "connected", | ||
| 288 | sessionId: completed.right.sessionId, | ||
| 289 | payload: { | ||
| 290 | type: "executor:oauth-result", | ||
| 291 | ok: true, | ||
| 292 | sessionId: completed.right.sessionId, | ||
| 293 | auth: completed.right.auth, | ||
| 294 | }, | ||
| 295 | }), | ||
| 296 | ); | ||
| 297 | } | ||
| 298 | |||
| 299 | const message = completed.left instanceof Error | ||
| 300 | ? completed.left.message | ||
| 301 | : "Failed completing OAuth"; | ||
| 282 | 302 | ||
| 283 | if (Either.isRight(completed)) { | ||
| 284 | return htmlResponse( | 303 | return htmlResponse( |
| 285 | sourceOAuthPopupResultDocument({ | 304 | sourceOAuthPopupResultDocument({ |
| 286 | title: "OAuth connected", | 305 | title: "OAuth failed", |
| 287 | message: "OAuth credentials are ready. Return to the source form to finish saving.", | 306 | message, |
| 288 | status: "connected", | 307 | status: "failed", |
| 289 | sessionId: completed.right.sessionId, | 308 | sessionId: "failed", |
| 290 | payload: { | 309 | payload: { |
| 291 | type: "executor:oauth-result", | 310 | type: "executor:oauth-result", |
| 292 | ok: true, | 311 | ok: false, |
| 293 | sessionId: completed.right.sessionId, | 312 | sessionId: null, |
| 294 | auth: completed.right.auth, | 313 | error: message, |
| 295 | }, | 314 | }, |
| 296 | }), | 315 | }), |
| 316 | 500, | ||
| 297 | ); | 317 | ); |
| 298 | } | 318 | }), |
| 299 | 319 | ), | |
| 300 | const message = completed.left instanceof Error | ||
| 301 | ? completed.left.message | ||
| 302 | : "Failed completing OAuth"; | ||
| 303 | |||
| 304 | return htmlResponse( | ||
| 305 | sourceOAuthPopupResultDocument({ | ||
| 306 | title: "OAuth failed", | ||
| 307 | message, | ||
| 308 | status: "failed", | ||
| 309 | sessionId: "failed", | ||
| 310 | payload: { | ||
| 311 | type: "executor:oauth-result", | ||
| 312 | ok: false, | ||
| 313 | sessionId: null, | ||
| 314 | error: message, | ||
| 315 | }, | ||
| 316 | }), | ||
| 317 | 500, | ||
| 318 | ); | ||
| 319 | }), | ||
| 320 | ), | 320 | ), |
| 321 | ); | 321 | ); |
| @@ -2,7 +2,7 @@ import { HttpApiEndpoint, HttpApiGroup, HttpApiSchema } from "@effect/platform"; · 1 unmodified line | |||
| 2 | import { | 2 | import { |
| 3 | CreatePolicyPayloadSchema, | 3 | CreatePolicyPayloadSchema, |
| 4 | UpdatePolicyPayloadSchema, | 4 | UpdatePolicyPayloadSchema, |
| 5 | } from "@executor/platform-sdk/policies/contracts"; | 5 | } from "@executor/platform-sdk/contracts"; |
| 6 | import { | 6 | import { |
| 7 | ControlPlaneBadRequestError, | 7 | ControlPlaneBadRequestError, |
| 8 | ControlPlaneForbiddenError, | 8 | ControlPlaneForbiddenError, |
| @@ -20,7 +20,7 @@ import * as Schema from "effect/Schema"; · 11 unmodified lines | |||
| 20 | export type { | 20 | export type { |
| 21 | CreatePolicyPayload, | 21 | CreatePolicyPayload, |
| 22 | UpdatePolicyPayload, | 22 | UpdatePolicyPayload, |
| 23 | } from "@executor/platform-sdk/policies/contracts"; | 23 | } from "@executor/platform-sdk/contracts"; |
| 24 | 24 | ||
| 25 | export { | 25 | export { |
| 26 | CreatePolicyPayloadSchema, | 26 | CreatePolicyPayloadSchema, |
| @@ -1,12 +1,5 @@ | |||
| 1 | import { HttpApiBuilder } from "@effect/platform"; | 1 | import { HttpApiBuilder } from "@effect/platform"; |
| 2 | import * as Effect from "effect/Effect"; | 2 | import * as Effect from "effect/Effect"; |
| 3 | import { | ||
| 4 | createPolicy, | ||
| 5 | getPolicy, | ||
| 6 | listPolicies, | ||
| 7 | removePolicy, | ||
| 8 | updatePolicy, | ||
| 9 | } from "@executor/platform-sdk"; | ||
| 10 | 3 | ||
| 11 | import { ControlPlaneApi } from "../api"; | 4 | import { ControlPlaneApi } from "../api"; |
| 12 | import { resolveRequestedLocalWorkspace } from "../local-context"; | 5 | import { resolveRequestedLocalWorkspace } from "../local-context"; |
| @@ -18,7 +11,7 @@ export const ControlPlanePoliciesLive = HttpApiBuilder.group( · 5 unmodified lines | |||
| 18 | handlers | 11 | handlers |
| 19 | .handle("list", ({ path }) => | 12 | .handle("list", ({ path }) => |
| 20 | resolveRequestedLocalWorkspace("policies.list", path.workspaceId).pipe( | 13 | resolveRequestedLocalWorkspace("policies.list", path.workspaceId).pipe( |
| 21 | Effect.zipRight(listPolicies(path.workspaceId)), | 14 | Effect.flatMap((executor) => executor.effect.policies.list()), |
| 22 | ), | 15 | ), |
| 23 | ) | 16 | ) |
| 24 | .handle("create", ({ path, payload }) => | 17 | .handle("create", ({ path, payload }) => |
| @@ -26,19 +19,12 @@ export const ControlPlanePoliciesLive = HttpApiBuilder.group( · 1 unmodified line | |||
| 26 | "policies.create", | 19 | "policies.create", |
| 27 | path.workspaceId, | 20 | path.workspaceId, |
| 28 | ).pipe( | 21 | ).pipe( |
| 29 | Effect.zipRight( | 22 | Effect.flatMap((executor) => executor.effect.policies.create(payload)), |
| 30 | createPolicy({ workspaceId: path.workspaceId, payload }), | ||
| 31 | ), | ||
| 32 | ), | 23 | ), |
| 33 | ) | 24 | ) |
| 34 | .handle("get", ({ path }) => | 25 | .handle("get", ({ path }) => |
| 35 | resolveRequestedLocalWorkspace("policies.get", path.workspaceId).pipe( | 26 | resolveRequestedLocalWorkspace("policies.get", path.workspaceId).pipe( |
| 36 | Effect.zipRight( | 27 | Effect.flatMap((executor) => executor.effect.policies.get(path.policyId)), |
| 37 | getPolicy({ | ||
| 38 | workspaceId: path.workspaceId, | ||
| 39 | policyId: path.policyId, | ||
| 40 | }), | ||
| 41 | ), | ||
| 42 | ), | 28 | ), |
| 43 | ) | 29 | ) |
| 44 | .handle("update", ({ path, payload }) => | 30 | .handle("update", ({ path, payload }) => |
| @@ -46,12 +32,8 @@ export const ControlPlanePoliciesLive = HttpApiBuilder.group( · 1 unmodified line | |||
| 46 | "policies.update", | 32 | "policies.update", |
| 47 | path.workspaceId, | 33 | path.workspaceId, |
| 48 | ).pipe( | 34 | ).pipe( |
| 49 | Effect.zipRight( | 35 | Effect.flatMap((executor) => |
| 50 | updatePolicy({ | 36 | executor.effect.policies.update(path.policyId, payload) |
| 51 | workspaceId: path.workspaceId, | ||
| 52 | policyId: path.policyId, | ||
| 53 | payload, | ||
| 54 | }), | ||
| 55 | ), | 37 | ), |
| 56 | ), | 38 | ), |
| 57 | ) | 39 | ) |
| @@ -60,12 +42,10 @@ export const ControlPlanePoliciesLive = HttpApiBuilder.group( · 2 unmodified lines | |||
| 60 | "policies.remove", | 42 | "policies.remove", |
| 61 | path.workspaceId, | 43 | path.workspaceId, |
| 62 | ).pipe( | 44 | ).pipe( |
| 63 | Effect.zipRight( | 45 | Effect.flatMap((executor) => executor.effect.policies.remove(path.policyId)), |
| 64 | removePolicy({ | 46 | Effect.map((result) => ({ |
| 65 | workspaceId: path.workspaceId, | 47 | removed: result.removed, |
| 66 | policyId: path.policyId, | 48 | })), |
| 67 | }), | ||
| 68 | ), | ||
| 69 | ), | 49 | ), |
| 70 | ), | 50 | ), |
| 71 | ); | 51 | ); |
| @@ -12,7 +12,7 @@ import { · 11 unmodified lines | |||
| 12 | DiscoverSourcePayloadSchema, | 12 | DiscoverSourcePayloadSchema, |
| 13 | UpdateSourcePayloadSchema, | 13 | UpdateSourcePayloadSchema, |
| 14 | WorkspaceOauthClientQuerySchema, | 14 | WorkspaceOauthClientQuerySchema, |
| 15 | } from "@executor/platform-sdk/sources/contracts"; | 15 | } from "@executor/platform-sdk/contracts"; |
| 16 | import { | 16 | import { |
| 17 | ControlPlaneBadRequestError, | 17 | ControlPlaneBadRequestError, |
| 18 | ControlPlaneForbiddenError, | 18 | ControlPlaneForbiddenError, |
| @@ -44,7 +44,7 @@ export type { · 25 unmodified lines | |||
| 44 | CreateWorkspaceOauthClientPayload, | 44 | CreateWorkspaceOauthClientPayload, |
| 45 | DiscoverSourcePayload, | 45 | DiscoverSourcePayload, |
| 46 | UpdateSourcePayload, | 46 | UpdateSourcePayload, |
| 47 | } from "@executor/platform-sdk/sources/contracts"; | 47 | } from "@executor/platform-sdk/contracts"; |
| 48 | 48 | ||
| 49 | export { | 49 | export { |
| 50 | ConnectSourceBatchPayloadSchema, | 50 | ConnectSourceBatchPayloadSchema, |
| @@ -7,28 +7,18 @@ import type { · 6 unmodified lines | |||
| 7 | ExecutionInteraction, | 7 | ExecutionInteraction, |
| 8 | Source, | 8 | Source, |
| 9 | WorkspaceId, | 9 | WorkspaceId, |
| 10 | WorkspaceOauthClient, | ||
| 10 | } from "@executor/platform-sdk/schema"; | 11 | } from "@executor/platform-sdk/schema"; |
| 12 | import type { | ||
| 13 | ExecutorMcpSourceInput, | ||
| 14 | ExecutorSourceInput, | ||
| 15 | } from "@executor/platform-sdk"; | ||
| 11 | import * as Effect from "effect/Effect"; | 16 | import * as Effect from "effect/Effect"; |
| 12 | 17 | ||
| 13 | import { | ||
| 14 | completeSourceCredentialSetup, | ||
| 15 | createSource, | ||
| 16 | discoverSource, | ||
| 17 | discoverSourceInspectionTools, | ||
| 18 | getSource, | ||
| 19 | getSourceCredentialInteraction, | ||
| 20 | getSourceInspection, | ||
| 21 | getSourceInspectionToolDetail, | ||
| 22 | listSources, | ||
| 23 | removeSource, | ||
| 24 | submitSourceCredentialInteraction, | ||
| 25 | updateSource, | ||
| 26 | } from "@executor/platform-sdk"; | ||
| 27 | import { | 18 | import { |
| 28 | sourceAdapterRequiresInteractiveConnect, | 19 | sourceAdapterRequiresInteractiveConnect, |
| 29 | RuntimeSourceAuthServiceTag, | ||
| 30 | type ExecutorAddSourceInput, | ||
| 31 | } from "@executor/platform-sdk/runtime"; | 20 | } from "@executor/platform-sdk/runtime"; |
| 21 | import { WorkspaceOauthClientIdSchema } from "@executor/platform-sdk/schema"; | ||
| 32 | 22 | ||
| 33 | import { | 23 | import { |
| 34 | ControlPlaneBadRequestError, | 24 | ControlPlaneBadRequestError, |
| @@ -37,7 +27,10 @@ import { · 2 unmodified lines | |||
| 37 | } from "../errors"; | 27 | } from "../errors"; |
| 38 | import { ControlPlaneApi } from "../api"; | 28 | import { ControlPlaneApi } from "../api"; |
| 39 | import type { ConnectSourcePayload } from "./api"; | 29 | import type { ConnectSourcePayload } from "./api"; |
| 40 | import { resolveRequestedLocalWorkspace } from "../local-context"; | 30 | import { |
| 31 | getControlPlaneExecutor, | ||
| 32 | resolveRequestedLocalWorkspace, | ||
| 33 | } from "../local-context"; | ||
| 41 | 34 | ||
| 42 | const readHeader = (headers: unknown, name: string): string | null => { | 35 | const readHeader = (headers: unknown, name: string): string | null => { |
| 43 | if (headers == null || typeof headers !== "object") { | 36 | if (headers == null || typeof headers !== "object") { |
| @@ -93,6 +86,80 @@ const isInteractiveConnectPayload = ( · 49 unmodified lines | |||
| 93 | payload.kind === undefined || | 86 | payload.kind === undefined || |
| 94 | sourceAdapterRequiresInteractiveConnect(payload.kind); | 87 | sourceAdapterRequiresInteractiveConnect(payload.kind); |
| 95 | 88 | ||
| 89 | const nullToUndefined = <T>(value: T | null | undefined): T | undefined => | ||
| 90 | value ?? undefined; | ||
| 91 | |||
| 92 | const toWorkspaceOauthClientId = ( | ||
| 93 | value: string | null | undefined, | ||
| 94 | ): WorkspaceOauthClient["id"] | null | undefined => | ||
| 95 | value == null ? value : WorkspaceOauthClientIdSchema.make(value); | ||
| 96 | |||
| 97 | const toExecutorSourceInput = ( | ||
| 98 | payload: ConnectSourcePayload, | ||
| 99 | ): ExecutorSourceInput | null => { | ||
| 100 | if (isInteractiveConnectPayload(payload)) { | ||
| 101 | return null; | ||
| 102 | } | ||
| 103 | |||
| 104 | switch (payload.kind) { | ||
| 105 | case "openapi": | ||
| 106 | return { | ||
| 107 | kind: "openapi", | ||
| 108 | endpoint: payload.endpoint, | ||
| 109 | specUrl: payload.specUrl, | ||
| 110 | name: payload.name, | ||
| 111 | namespace: payload.namespace, | ||
| 112 | importAuthPolicy: nullToUndefined(payload.importAuthPolicy), | ||
| 113 | importAuth: payload.importAuth, | ||
| 114 | auth: payload.auth, | ||
| 115 | }; | ||
| 116 | case "graphql": | ||
| 117 | return { | ||
| 118 | kind: "graphql", | ||
| 119 | endpoint: payload.endpoint, | ||
| 120 | name: payload.name, | ||
| 121 | namespace: payload.namespace, | ||
| 122 | importAuthPolicy: nullToUndefined(payload.importAuthPolicy), | ||
| 123 | importAuth: payload.importAuth, | ||
| 124 | auth: payload.auth, | ||
| 125 | }; | ||
| 126 | case "google_discovery": | ||
| 127 | return { | ||
| 128 | kind: "google_discovery", | ||
| 129 | service: payload.service, | ||
| 130 | version: payload.version, | ||
| 131 | discoveryUrl: payload.discoveryUrl, | ||
| 132 | scopes: payload.scopes, | ||
| 133 | workspaceOauthClientId: toWorkspaceOauthClientId( | ||
| 134 | payload.workspaceOauthClientId, | ||
| 135 | ), | ||
| 136 | oauthClient: payload.oauthClient, | ||
| 137 | name: payload.name, | ||
| 138 | namespace: payload.namespace, | ||
| 139 | importAuthPolicy: nullToUndefined(payload.importAuthPolicy), | ||
| 140 | importAuth: payload.importAuth, | ||
| 141 | auth: payload.auth, | ||
| 142 | }; | ||
| 143 | } | ||
| 144 | }; | ||
| 145 | |||
| 146 | const toExecutorMcpSourceInput = ( | ||
| 147 | payload: Extract<ConnectSourcePayload, { kind?: "mcp" }>, | ||
| 148 | baseUrl: string | null, | ||
| 149 | ): ExecutorMcpSourceInput => ({ | ||
| 150 | endpoint: payload.endpoint, | ||
| 151 | name: payload.name, | ||
| 152 | namespace: payload.namespace, | ||
| 153 | transport: payload.transport, | ||
| 154 | queryParams: payload.queryParams, | ||
| 155 | headers: payload.headers, | ||
| 156 | command: payload.command, | ||
| 157 | args: payload.args, | ||
| 158 | env: payload.env, | ||
| 159 | cwd: payload.cwd, | ||
| 160 | baseUrl, | ||
| 161 | }); | ||
| 162 | |||
| 96 | const escapeHtml = (value: string): string => | 163 | const escapeHtml = (value: string): string => |
| 97 | value | 164 | value |
| 98 | .replaceAll("&", "&") | 165 | .replaceAll("&", "&") |
| @@ -595,8 +662,13 @@ const sourceOAuthPopupResultDocument = (input: { · 496 unmodified lines | |||
| 595 | </body> | 662 | </body> |
| 596 | </html>`; | 663 | </html>`; |
| 597 | 664 | ||
| 598 | const htmlResponse = (html: string, status = 200) => | 665 | const htmlResponse = ( |
| 599 | HttpServerResponse.html(html).pipe(HttpServerResponse.setStatus(status)); | 666 | html: string, |
| 667 | status = 200, | ||
| 668 | ): ReturnType<typeof HttpServerResponse.html> => | ||
| 669 | HttpServerResponse.html(html).pipe( | ||
| 670 | HttpServerResponse.setStatus(status), | ||
| 671 | ) as ReturnType<typeof HttpServerResponse.html>; | ||
| 600 | 672 | ||
| 601 | const credentialErrorResponse = (input: { | 673 | const credentialErrorResponse = (input: { |
| 602 | title: string; | 674 | title: string; |
| @@ -636,11 +708,16 @@ const credentialSubmitErrorResponse = (input: { · 33 unmodified lines | |||
| 636 | message: string; | 708 | message: string; |
| 637 | status: number; | 709 | status: number; |
| 638 | }) => | 710 | }) => |
| 639 | getSourceCredentialInteraction({ | 711 | resolveRequestedLocalWorkspace( |
| 640 | workspaceId: input.workspaceId, | 712 | "sources.credentialSubmit", |
| 641 | sourceId: input.sourceId, | 713 | input.workspaceId, |
| 642 | interactionId: input.interactionId, | 714 | ).pipe( |
| 643 | }).pipe( | 715 | Effect.flatMap((executor) => |
| 716 | executor.effect.local.credentials.get({ | ||
| 717 | sourceId: input.sourceId, | ||
| 718 | interactionId: input.interactionId, | ||
| 719 | }), | ||
| 720 | ), | ||
| 644 | Effect.match({ | 721 | Effect.match({ |
| 645 | onFailure: () => | 722 | onFailure: () => |
| 646 | credentialErrorResponse({ | 723 | credentialErrorResponse({ |
| @@ -671,53 +748,45 @@ export const ControlPlaneSourcesLive = HttpApiBuilder.group( · 24 unmodified lines | |||
| 671 | (handlers) => | 748 | (handlers) => |
| 672 | handlers | 749 | handlers |
| 673 | .handle("discover", ({ payload }) => | 750 | .handle("discover", ({ payload }) => |
| 674 | discoverSource({ | 751 | Effect.flatMap(getControlPlaneExecutor(), (executor) => |
| 675 | url: payload.url, | 752 | executor.effect.sources.discover({ |
| 676 | probeAuth: payload.probeAuth, | 753 | url: payload.url, |
| 677 | }).pipe( | 754 | probeAuth: payload.probeAuth, |
| 678 | Effect.catchAll((cause) => | 755 | }).pipe( |
| 679 | Effect.fail(toBadRequestError("sources.discover", cause)), | 756 | Effect.catchAll((cause) => |
| 680 | ), | 757 | Effect.fail(toBadRequestError("sources.discover", cause)), |
| 681 | ), | 758 | ), |
| 759 | ) | ||
| 760 | ) | ||
| 682 | ) | 761 | ) |
| 683 | .handle("connect", ({ path, payload }) => | 762 | .handle("connect", ({ path, payload }) => |
| 684 | resolveRequestedLocalWorkspace( | 763 | resolveRequestedLocalWorkspace( |
| 685 | "sources.connect", | 764 | "sources.connect", |
| 686 | path.workspaceId, | 765 | path.workspaceId, |
| 687 | ).pipe( | 766 | ).pipe( |
| 688 | Effect.flatMap((runtimeLocalWorkspace) => | 767 | Effect.flatMap((executor) => |
| 689 | Effect.gen(function* () { | 768 | Effect.gen(function* () { |
| 690 | const request = yield* HttpServerRequest.HttpServerRequest; | 769 | const request = yield* HttpServerRequest.HttpServerRequest; |
| 691 | const sourceAuthService = yield* RuntimeSourceAuthServiceTag; | ||
| 692 | const baseUrl = resolveRequestOrigin(request); | 770 | const baseUrl = resolveRequestOrigin(request); |
| 693 | 771 | ||
| 694 | if (isInteractiveConnectPayload(payload)) { | 772 | if (isInteractiveConnectPayload(payload)) { |
| 695 | return yield* sourceAuthService.connectMcpSource({ | 773 | return yield* executor.effect.sources.connect( |
| 696 | workspaceId: path.workspaceId, | 774 | toExecutorMcpSourceInput(payload, baseUrl), |
| 697 | actorAccountId: runtimeLocalWorkspace.installation.accountId, | 775 | ); |
| 698 | endpoint: payload.endpoint, | ||
| 699 | name: payload.name, | ||
| 700 | namespace: payload.namespace, | ||
| 701 | transport: payload.transport, | ||
| 702 | queryParams: payload.queryParams, | ||
| 703 | headers: payload.headers, | ||
| 704 | command: payload.command, | ||
| 705 | args: payload.args, | ||
| 706 | env: payload.env, | ||
| 707 | cwd: payload.cwd, | ||
| 708 | baseUrl, | ||
| 709 | }); | ||
| 710 | } | 776 | } |
| 711 | 777 | ||
| 712 | return yield* sourceAuthService.addExecutorSource( | 778 | const sourceInput = toExecutorSourceInput(payload); |
| 713 | { | 779 | if (sourceInput) { |
| 714 | workspaceId: path.workspaceId, | 780 | return yield* executor.effect.sources.add(sourceInput, { |
| 715 | actorAccountId: runtimeLocalWorkspace.installation.accountId, | 781 | baseUrl, |
| 716 | executionId: null, | 782 | }); |
| 717 | interactionId: null, | 783 | } |
| 718 | ...(payload as Record<string, unknown>), | 784 | |
| 719 | } as ExecutorAddSourceInput, | 785 | return yield* Effect.fail( |
| 720 | { baseUrl }, | 786 | toBadRequestError( |
| 787 | "sources.connect", | ||
| 788 | new Error("Unsupported source connect payload"), | ||
| 789 | ), | ||
| 721 | ); | 790 | ); |
| 722 | }).pipe( | 791 | }).pipe( |
| 723 | Effect.catchAll((cause) => | 792 | Effect.catchAll((cause) => |
| @@ -732,20 +801,12 @@ export const ControlPlaneSourcesLive = HttpApiBuilder.group( · 8 unmodified lines | |||
| 732 | "sources.connectBatch", | 801 | "sources.connectBatch", |
| 733 | path.workspaceId, | 802 | path.workspaceId, |
| 734 | ).pipe( | 803 | ).pipe( |
| 735 | Effect.flatMap((runtimeLocalWorkspace) => | 804 | Effect.flatMap((executor) => |
| 736 | Effect.gen(function* () { | 805 | Effect.gen(function* () { |
| 737 | const request = yield* HttpServerRequest.HttpServerRequest; | 806 | const request = yield* HttpServerRequest.HttpServerRequest; |
| 738 | const sourceAuthService = yield* RuntimeSourceAuthServiceTag; | 807 | return yield* executor.effect.sources.connectBatch({ |
| 739 | const baseUrl = resolveRequestOrigin(request); | 808 | ...payload, |
| 740 | 809 | baseUrl: resolveRequestOrigin(request), | |
| 741 | return yield* sourceAuthService.connectGoogleDiscoveryBatch({ | ||
| 742 | workspaceId: path.workspaceId, | ||
| 743 | actorAccountId: runtimeLocalWorkspace.installation.accountId, | ||
| 744 | executionId: null, | ||
| 745 | interactionId: null, | ||
| 746 | workspaceOauthClientId: payload.workspaceOauthClientId, | ||
| 747 | sources: payload.sources, | ||
| 748 | baseUrl, | ||
| 749 | }); | 810 | }); |
| 750 | }).pipe( | 811 | }).pipe( |
| 751 | Effect.catchAll((cause) => | 812 | Effect.catchAll((cause) => |
| @@ -760,20 +821,14 @@ export const ControlPlaneSourcesLive = HttpApiBuilder.group( · 8 unmodified lines | |||
| 760 | "sources.listWorkspaceOauthClients", | 821 | "sources.listWorkspaceOauthClients", |
| 761 | path.workspaceId, | 822 | path.workspaceId, |
| 762 | ).pipe( | 823 | ).pipe( |
| 763 | Effect.flatMap(() => | 824 | Effect.flatMap((executor) => |
| 764 | Effect.gen(function* () { | 825 | executor.effect.sources.oauthClients.list(urlParams.providerKey).pipe( |
| 765 | const sourceAuthService = yield* RuntimeSourceAuthServiceTag; | ||
| 766 | return yield* sourceAuthService.listWorkspaceOauthClients({ | ||
| 767 | workspaceId: path.workspaceId, | ||
| 768 | providerKey: urlParams.providerKey, | ||
| 769 | }); | ||
| 770 | }).pipe( | ||
| 771 | Effect.catchAll((cause) => | 826 | Effect.catchAll((cause) => |
| 772 | Effect.fail( | 827 | Effect.fail( |
| 773 | toBadRequestError("sources.listWorkspaceOauthClients", cause), | 828 | toBadRequestError("sources.listWorkspaceOauthClients", cause), |
| 774 | ), | 829 | ), |
| 775 | ), | 830 | ), |
| 776 | ), | 831 | ) |
| 777 | ), | 832 | ), |
| 778 | ), | 833 | ), |
| 779 | ) | 834 | ) |
| @@ -782,16 +837,8 @@ export const ControlPlaneSourcesLive = HttpApiBuilder.group( · 2 unmodified lines | |||
| 782 | "sources.createWorkspaceOauthClient", | 837 | "sources.createWorkspaceOauthClient", |
| 783 | path.workspaceId, | 838 | path.workspaceId, |
| 784 | ).pipe( | 839 | ).pipe( |
| 785 | Effect.flatMap(() => | 840 | Effect.flatMap((executor) => |
| 786 | Effect.gen(function* () { | 841 | executor.effect.sources.oauthClients.create(payload).pipe( |
| 787 | const sourceAuthService = yield* RuntimeSourceAuthServiceTag; | ||
| 788 | return yield* sourceAuthService.createWorkspaceOauthClient({ | ||
| 789 | workspaceId: path.workspaceId, | ||
| 790 | providerKey: payload.providerKey, | ||
| 791 | label: payload.label, | ||
| 792 | oauthClient: payload.oauthClient, | ||
| 793 | }); | ||
| 794 | }).pipe( | ||
| 795 | Effect.catchAll((cause) => | 842 | Effect.catchAll((cause) => |
| 796 | Effect.fail( | 843 | Effect.fail( |
| 797 | toBadRequestError( | 844 | toBadRequestError( |
| @@ -800,7 +847,7 @@ export const ControlPlaneSourcesLive = HttpApiBuilder.group( · 2 unmodified lines | |||
| 800 | ), | 847 | ), |
| 801 | ), | 848 | ), |
| 802 | ), | 849 | ), |
| 803 | ), | 850 | ) |
| 804 | ), | 851 | ), |
| 805 | ), | 852 | ), |
| 806 | ) | 853 | ) |
| @@ -809,17 +856,9 @@ export const ControlPlaneSourcesLive = HttpApiBuilder.group( · 2 unmodified lines | |||
| 809 | "sources.removeWorkspaceOauthClient", | 856 | "sources.removeWorkspaceOauthClient", |
| 810 | path.workspaceId, | 857 | path.workspaceId, |
| 811 | ).pipe( | 858 | ).pipe( |
| 812 | Effect.flatMap(() => | 859 | Effect.flatMap((executor) => |
| 813 | Effect.gen(function* () { | 860 | executor.effect.sources.oauthClients.remove(path.oauthClientId).pipe( |
| 814 | const sourceAuthService = yield* RuntimeSourceAuthServiceTag; | 861 | Effect.map((result) => ({ removed: result })), |
| 815 | const removed = | ||
| 816 | yield* sourceAuthService.removeWorkspaceOauthClient({ | ||
| 817 | workspaceId: path.workspaceId, | ||
| 818 | oauthClientId: path.oauthClientId, | ||
| 819 | }); | ||
| 820 | |||
| 821 | return { removed }; | ||
| 822 | }).pipe( | ||
| 823 | Effect.catchAll((cause) => | 862 | Effect.catchAll((cause) => |
| 824 | Effect.fail( | 863 | Effect.fail( |
| 825 | toBadRequestError( | 864 | toBadRequestError( |
| @@ -828,7 +867,7 @@ export const ControlPlaneSourcesLive = HttpApiBuilder.group( · 2 unmodified lines | |||
| 828 | ), | 867 | ), |
| 829 | ), | 868 | ), |
| 830 | ), | 869 | ), |
| 831 | ), | 870 | ) |
| 832 | ), | 871 | ), |
| 833 | ), | 872 | ), |
| 834 | ) | 873 | ) |
| @@ -837,60 +876,34 @@ export const ControlPlaneSourcesLive = HttpApiBuilder.group( · 2 unmodified lines | |||
| 837 | "sources.removeProviderAuthGrant", | 876 | "sources.removeProviderAuthGrant", |
| 838 | path.workspaceId, | 877 | path.workspaceId, |
| 839 | ).pipe( | 878 | ).pipe( |
| 840 | Effect.flatMap(() => | 879 | Effect.flatMap((executor) => |
| 841 | Effect.gen(function* () { | 880 | executor.effect.sources.providerGrants.remove(path.grantId).pipe( |
| 842 | const sourceAuthService = yield* RuntimeSourceAuthServiceTag; | 881 | Effect.map((result) => ({ removed: result })), |
| 843 | const removed = yield* sourceAuthService | 882 | Effect.catchAll((cause) => |
| 844 | .removeProviderAuthGrant({ | 883 | Effect.fail( |
| 845 | workspaceId: path.workspaceId, | 884 | toBadRequestError( |
| 846 | grantId: path.grantId, | 885 | "sources.removeProviderAuthGrant", |
| 847 | }) | 886 | cause, |
| 848 | .pipe( | ||
| 849 | Effect.catchAll((cause) => | ||
| 850 | Effect.fail( | ||
| 851 | toBadRequestError( | ||
| 852 | "sources.removeProviderAuthGrant", | ||
| 853 | cause, | ||
| 854 | ), | ||
| 855 | ), | ||
| 856 | ), | 887 | ), |
| 857 | ); | 888 | ), |
| 858 | 889 | ), | |
| 859 | return { removed }; | 890 | ) |
| 860 | }), | ||
| 861 | ), | 891 | ), |
| 862 | ), | 892 | ), |
| 863 | ) | 893 | ) |
| 864 | .handle("list", ({ path }) => | 894 | .handle("list", ({ path }) => |
| 865 | resolveRequestedLocalWorkspace("sources.list", path.workspaceId).pipe( | 895 | resolveRequestedLocalWorkspace("sources.list", path.workspaceId).pipe( |
| 866 | Effect.flatMap((runtimeLocalWorkspace) => | 896 | Effect.flatMap((executor) => executor.effect.sources.list()), |
| 867 | listSources({ | ||
| 868 | workspaceId: path.workspaceId, | ||
| 869 | accountId: runtimeLocalWorkspace.installation.accountId, | ||
| 870 | }), | ||
| 871 | ), | ||
| 872 | ), | 897 | ), |
| 873 | ) | 898 | ) |
| 874 | .handle("create", ({ path, payload }) => | 899 | .handle("create", ({ path, payload }) => |
| 875 | resolveRequestedLocalWorkspace("sources.create", path.workspaceId).pipe( | 900 | resolveRequestedLocalWorkspace("sources.create", path.workspaceId).pipe( |
| 876 | Effect.flatMap((runtimeLocalWorkspace) => | 901 | Effect.flatMap((executor) => executor.effect.sources.create(payload)), |
| 877 | createSource({ | ||
| 878 | workspaceId: path.workspaceId, | ||
| 879 | accountId: runtimeLocalWorkspace.installation.accountId, | ||
| 880 | payload, | ||
| 881 | }), | ||
| 882 | ), | ||
| 883 | ), | 902 | ), |
| 884 | ) | 903 | ) |
| 885 | .handle("get", ({ path }) => | 904 | .handle("get", ({ path }) => |
| 886 | resolveRequestedLocalWorkspace("sources.get", path.workspaceId).pipe( | 905 | resolveRequestedLocalWorkspace("sources.get", path.workspaceId).pipe( |
| 887 | Effect.flatMap((runtimeLocalWorkspace) => | 906 | Effect.flatMap((executor) => executor.effect.sources.get(path.sourceId)), |
| 888 | getSource({ | ||
| 889 | workspaceId: path.workspaceId, | ||
| 890 | sourceId: path.sourceId, | ||
| 891 | accountId: runtimeLocalWorkspace.installation.accountId, | ||
| 892 | }), | ||
| 893 | ), | ||
| 894 | ), | 907 | ), |
| 895 | ) | 908 | ) |
| 896 | .handle("inspection", ({ path }) => | 909 | .handle("inspection", ({ path }) => |
| @@ -898,11 +911,8 @@ export const ControlPlaneSourcesLive = HttpApiBuilder.group( · 1 unmodified line | |||
| 898 | "sources.inspection", | 911 | "sources.inspection", |
| 899 | path.workspaceId, | 912 | path.workspaceId, |
| 900 | ).pipe( | 913 | ).pipe( |
| 901 | Effect.zipRight( | 914 | Effect.flatMap((executor) => |
| 902 | getSourceInspection({ | 915 | executor.effect.sources.inspection.get(path.sourceId), |
| 903 | workspaceId: path.workspaceId, | ||
| 904 | sourceId: path.sourceId, | ||
| 905 | }), | ||
| 906 | ), | 916 | ), |
| 907 | ), | 917 | ), |
| 908 | ) | 918 | ) |
| @@ -911,12 +921,11 @@ export const ControlPlaneSourcesLive = HttpApiBuilder.group( · 2 unmodified lines | |||
| 911 | "sources.inspection_tool", | 921 | "sources.inspection_tool", |
| 912 | path.workspaceId, | 922 | path.workspaceId, |
| 913 | ).pipe( | 923 | ).pipe( |
| 914 | Effect.zipRight( | 924 | Effect.flatMap((executor) => |
| 915 | getSourceInspectionToolDetail({ | 925 | executor.effect.sources.inspection.tool({ |
| 916 | workspaceId: path.workspaceId, | 926 | sourceId: path.sourceId, |
| 917 | sourceId: path.sourceId, | 927 | toolPath: path.toolPath, |
| 918 | toolPath: path.toolPath, | 928 | }), |
| 919 | }), | ||
| 920 | ), | 929 | ), |
| 921 | ), | 930 | ), |
| 922 | ) | 931 | ) |
| @@ -925,43 +934,38 @@ export const ControlPlaneSourcesLive = HttpApiBuilder.group( · 2 unmodified lines | |||
| 925 | "sources.inspection_discover", | 934 | "sources.inspection_discover", |
| 926 | path.workspaceId, | 935 | path.workspaceId, |
| 927 | ).pipe( | 936 | ).pipe( |
| 928 | Effect.zipRight( | 937 | Effect.flatMap((executor) => |
| 929 | discoverSourceInspectionTools({ | 938 | executor.effect.sources.inspection.discover({ |
| 930 | workspaceId: path.workspaceId, | 939 | sourceId: path.sourceId, |
| 931 | sourceId: path.sourceId, | 940 | payload, |
| 932 | payload, | 941 | }), |
| 933 | }), | ||
| 934 | ), | 942 | ), |
| 935 | ), | 943 | ), |
| 936 | ) | 944 | ) |
| 937 | .handle("update", ({ path, payload }) => | 945 | .handle("update", ({ path, payload }) => |
| 938 | resolveRequestedLocalWorkspace("sources.update", path.workspaceId).pipe( | 946 | resolveRequestedLocalWorkspace("sources.update", path.workspaceId).pipe( |
| 939 | Effect.flatMap((runtimeLocalWorkspace) => | 947 | Effect.flatMap((executor) => |
| 940 | updateSource({ | 948 | executor.effect.sources.update(path.sourceId, payload) |
| 941 | workspaceId: path.workspaceId, | ||
| 942 | sourceId: path.sourceId, | ||
| 943 | accountId: runtimeLocalWorkspace.installation.accountId, | ||
| 944 | payload, | ||
| 945 | }), | ||
| 946 | ), | 949 | ), |
| 947 | ), | 950 | ), |
| 948 | ) | 951 | ) |
| 949 | .handle("remove", ({ path }) => | 952 | .handle("remove", ({ path }) => |
| 950 | resolveRequestedLocalWorkspace("sources.remove", path.workspaceId).pipe( | 953 | resolveRequestedLocalWorkspace("sources.remove", path.workspaceId).pipe( |
| 951 | Effect.zipRight( | 954 | Effect.flatMap((executor) => executor.effect.sources.remove(path.sourceId)), |
| 952 | removeSource({ | 955 | Effect.map((result) => ({ removed: result.removed })), |
| 953 | workspaceId: path.workspaceId, | ||
| 954 | sourceId: path.sourceId, | ||
| 955 | }), | ||
| 956 | ), | ||
| 957 | ), | 956 | ), |
| 958 | ) | 957 | ) |
| 959 | .handle("credentialPage", ({ path, urlParams }) => | 958 | .handle("credentialPage", ({ path, urlParams }) => |
| 960 | getSourceCredentialInteraction({ | 959 | resolveRequestedLocalWorkspace( |
| 961 | workspaceId: path.workspaceId, | 960 | "sources.credentialPage", |
| 962 | sourceId: path.sourceId, | 961 | path.workspaceId, |
| 963 | interactionId: urlParams.interactionId, | 962 | ).pipe( |
| 964 | }).pipe( | 963 | Effect.flatMap((executor) => |
| 964 | executor.effect.local.credentials.get({ | ||
| 965 | sourceId: path.sourceId, | ||
| 966 | interactionId: urlParams.interactionId, | ||
| 967 | }), | ||
| 968 | ), | ||
| 965 | Effect.map((interaction) => | 969 | Effect.map((interaction) => |
| 966 | htmlResponse( | 970 | htmlResponse( |
| 967 | credentialPageDocument({ | 971 | credentialPageDocument({ |
| @@ -976,39 +980,44 @@ export const ControlPlaneSourcesLive = HttpApiBuilder.group( · 8 unmodified lines | |||
| 976 | }), | 980 | }), |
| 977 | ), | 981 | ), |
| 978 | ), | 982 | ), |
| 979 | Effect.catchTags({ | 983 | Effect.catchAll((error) => |
| 980 | ControlPlaneNotFoundError: (error) => | 984 | Effect.succeed( |
| 981 | Effect.succeed( | 985 | credentialErrorResponse({ |
| 982 | credentialErrorResponse({ | 986 | title: |
| 983 | title: "Source Credential Request Unavailable", | 987 | error instanceof ControlPlaneNotFoundError |
| 984 | message: error.message, | 988 | ? "Source Credential Request Unavailable" |
| 985 | status: credentialErrorStatus(error), | 989 | : "Source Credential Request Failed", |
| 986 | }), | 990 | message: |
| 987 | ), | 991 | error instanceof Error ? error.message : "Source credential request failed", |
| 988 | ControlPlaneStorageError: (error) => | 992 | status: |
| 989 | Effect.succeed( | 993 | error instanceof ControlPlaneNotFoundError |
| 990 | credentialErrorResponse({ | 994 | || error instanceof ControlPlaneStorageError |
| 991 | title: "Source Credential Request Failed", | 995 | || error instanceof ControlPlaneBadRequestError |
| 992 | message: error.message, | 996 | ? credentialErrorStatus(error) |
| 993 | status: credentialErrorStatus(error), | 997 | : 500, |
| 994 | }), | 998 | }), |
| 995 | ), | 999 | ), |
| 996 | }), | 1000 | ), |
| 997 | ), | 1001 | ), |
| 998 | ) | 1002 | ) |
| 999 | .handle("credentialSubmit", ({ path, urlParams, payload }) => | 1003 | .handle("credentialSubmit", ({ path, urlParams, payload }) => |
| 1000 | submitSourceCredentialInteraction({ | 1004 | resolveRequestedLocalWorkspace( |
| 1001 | workspaceId: path.workspaceId, | 1005 | "sources.credentialSubmit", |
| 1002 | sourceId: path.sourceId, | 1006 | path.workspaceId, |
| 1003 | interactionId: urlParams.interactionId, | 1007 | ).pipe( |
| 1004 | action: | 1008 | Effect.flatMap((executor) => |
| 1005 | payload.action === "cancel" | 1009 | executor.effect.local.credentials.submit({ |
| 1006 | ? "cancel" | 1010 | sourceId: path.sourceId, |
| 1007 | : payload.action === "continue" | 1011 | interactionId: urlParams.interactionId, |
| 1008 | ? "continue" | 1012 | action: |
| 1009 | : "submit", | 1013 | payload.action === "cancel" |
| 1010 | token: payload.token, | 1014 | ? "cancel" |
| 1011 | }).pipe( | 1015 | : payload.action === "continue" |
| 1016 | ? "continue" | ||
| 1017 | : "submit", | ||
| 1018 | token: payload.token, | ||
| 1019 | }), | ||
| 1020 | ), | ||
| 1012 | Effect.map((result) => | 1021 | Effect.map((result) => |
| 1013 | htmlResponse( | 1022 | htmlResponse( |
| 1014 | credentialPageDocument({ | 1023 | credentialPageDocument({ |
| @@ -1037,43 +1046,49 @@ export const ControlPlaneSourcesLive = HttpApiBuilder.group( · 22 unmodified lines | |||
| 1037 | }), | 1046 | }), |
| 1038 | ), | 1047 | ), |
| 1039 | ), | 1048 | ), |
| 1040 | Effect.catchTags({ | 1049 | Effect.catchAll((error) => { |
| 1041 | ControlPlaneBadRequestError: (error) => | 1050 | if (error instanceof ControlPlaneBadRequestError) { |
| 1042 | credentialSubmitErrorResponse({ | 1051 | return credentialSubmitErrorResponse({ |
| 1043 | workspaceId: path.workspaceId, | 1052 | workspaceId: path.workspaceId, |
| 1044 | sourceId: path.sourceId, | 1053 | sourceId: path.sourceId, |
| 1045 | interactionId: urlParams.interactionId, | 1054 | interactionId: urlParams.interactionId, |
| 1046 | message: error.message, | 1055 | message: error.message, |
| 1047 | status: credentialErrorStatus(error), | 1056 | status: credentialErrorStatus(error), |
| 1057 | }); | ||
| 1058 | } | ||
| 1059 | |||
| 1060 | return Effect.succeed( | ||
| 1061 | credentialErrorResponse({ | ||
| 1062 | title: | ||
| 1063 | error instanceof ControlPlaneNotFoundError | ||
| 1064 | ? "Source Credential Request Unavailable" | ||
| 1065 | : "Source Credential Request Failed", | ||
| 1066 | message: | ||
| 1067 | error instanceof Error ? error.message : "Source credential request failed", | ||
| 1068 | status: | ||
| 1069 | error instanceof ControlPlaneNotFoundError | ||
| 1070 | || error instanceof ControlPlaneStorageError | ||
| 1071 | ? credentialErrorStatus(error) | ||
| 1072 | : 500, | ||
| 1048 | }), | 1073 | }), |
| 1049 | ControlPlaneNotFoundError: (error) => | 1074 | ); |
| 1050 | Effect.succeed( | ||
| 1051 | credentialErrorResponse({ | ||
| 1052 | title: "Source Credential Request Unavailable", | ||
| 1053 | message: error.message, | ||
| 1054 | status: credentialErrorStatus(error), | ||
| 1055 | }), | ||
| 1056 | ), | ||
| 1057 | ControlPlaneStorageError: (error) => | ||
| 1058 | Effect.succeed( | ||
| 1059 | credentialErrorResponse({ | ||
| 1060 | title: "Source Credential Request Failed", | ||
| 1061 | message: error.message, | ||
| 1062 | status: credentialErrorStatus(error), | ||
| 1063 | }), | ||
| 1064 | ), | ||
| 1065 | }), | 1075 | }), |
| 1066 | ), | 1076 | ), |
| 1067 | ) | 1077 | ) |
| 1068 | .handle("credentialComplete", ({ path, urlParams }) => | 1078 | .handle("credentialComplete", ({ path, urlParams }) => |
| 1069 | completeSourceCredentialSetup({ | 1079 | resolveRequestedLocalWorkspace( |
| 1070 | workspaceId: path.workspaceId, | 1080 | "sources.credentialComplete", |
| 1071 | sourceId: path.sourceId, | 1081 | path.workspaceId, |
| 1072 | state: urlParams.state, | 1082 | ).pipe( |
| 1073 | code: urlParams.code, | 1083 | Effect.flatMap((executor) => |
| 1074 | error: urlParams.error, | 1084 | executor.effect.local.credentials.complete({ |
| 1075 | errorDescription: urlParams.error_description, | 1085 | sourceId: path.sourceId, |
| 1076 | }).pipe( | 1086 | state: urlParams.state, |
| 1087 | code: urlParams.code, | ||
| 1088 | error: urlParams.error, | ||
| 1089 | errorDescription: urlParams.error_description, | ||
| 1090 | }), | ||
| 1091 | ), | ||
| 1077 | Effect.map((completed) => | 1092 | Effect.map((completed) => |
| 1078 | htmlResponse( | 1093 | htmlResponse( |
| 1079 | sourceOAuthPopupResultDocument({ | 1094 | sourceOAuthPopupResultDocument({ |
| @@ -1119,13 +1134,10 @@ export const ControlPlaneSourcesLive = HttpApiBuilder.group( · 39 unmodified lines | |||
| 1119 | "sources.providerOauthComplete", | 1134 | "sources.providerOauthComplete", |
| 1120 | path.workspaceId, | 1135 | path.workspaceId, |
| 1121 | ).pipe( | 1136 | ).pipe( |
| 1122 | Effect.flatMap((runtimeLocalWorkspace) => | 1137 | Effect.flatMap((executor) => |
| 1123 | Effect.gen(function* () { | 1138 | Effect.gen(function* () { |
| 1124 | const sourceAuthService = yield* RuntimeSourceAuthServiceTag; | 1139 | const completed = yield* executor.effect.oauth.completeProviderCallback({ |
| 1125 | const completed = | ||
| 1126 | yield* sourceAuthService.completeProviderOauthCallback({ | ||
| 1127 | workspaceId: path.workspaceId, | 1140 | workspaceId: path.workspaceId, |
| 1128 | actorAccountId: runtimeLocalWorkspace.installation.accountId, | ||
| 1129 | state: urlParams.state, | 1141 | state: urlParams.state, |
| 1130 | code: urlParams.code, | 1142 | code: urlParams.code, |
| 1131 | error: urlParams.error, | 1143 | error: urlParams.error, |
| @@ -1,4 +1,5 @@ | |||
| 1 | import { toTool, type ToolMap } from "@executor/codemode-core"; | 1 | import { toTool, type ToolMap } from "@executor/codemode-core"; |
| 2 | import type { Executor } from "@executor/platform-sdk"; | ||
| 2 | import { | 3 | import { |
| 3 | type AccountId, | 4 | type AccountId, |
| 4 | LocalInstallationSchema, | 5 | LocalInstallationSchema, |
| @@ -45,47 +46,39 @@ import { · 40 unmodified lines | |||
| 45 | UpdateSecretPayloadSchema, | 46 | UpdateSecretPayloadSchema, |
| 46 | UpdateSecretResultSchema, | 47 | UpdateSecretResultSchema, |
| 47 | type UpdateSecretPayload, | 48 | type UpdateSecretPayload, |
| 48 | } from "@executor/platform-sdk/local/contracts"; | 49 | } from "@executor/platform-sdk/contracts"; |
| 49 | import { | 50 | import { |
| 50 | createLocalSecret, | 51 | createLocalSecret, |
| 52 | createPolicy, | ||
| 51 | deleteLocalSecret, | 53 | deleteLocalSecret, |
| 54 | discoverSource, | ||
| 55 | discoverSourceInspectionTools, | ||
| 52 | getLocalInstanceConfig, | 56 | getLocalInstanceConfig, |
| 57 | getPolicy, | ||
| 58 | getSource, | ||
| 59 | getSourceInspection, | ||
| 60 | getSourceInspectionToolDetail, | ||
| 53 | listLocalSecrets, | 61 | listLocalSecrets, |
| 62 | listPolicies, | ||
| 63 | listSources, | ||
| 64 | removePolicy, | ||
| 65 | removeSource, | ||
| 54 | updateLocalSecret, | 66 | updateLocalSecret, |
| 55 | } from "@executor/platform-sdk/local/secrets"; | 67 | updatePolicy, |
| 68 | updateSource, | ||
| 69 | } from "@executor/platform-sdk/operations"; | ||
| 56 | import { | 70 | import { |
| 57 | CreatePolicyPayloadSchema, | 71 | CreatePolicyPayloadSchema, |
| 58 | type CreatePolicyPayload, | 72 | type CreatePolicyPayload, |
| 59 | type UpdatePolicyPayload, | 73 | type UpdatePolicyPayload, |
| 60 | UpdatePolicyPayloadSchema, | 74 | UpdatePolicyPayloadSchema, |
| 61 | } from "@executor/platform-sdk/policies/contracts"; | 75 | } from "@executor/platform-sdk/contracts"; |
| 62 | import { | ||
| 63 | createPolicy, | ||
| 64 | getPolicy, | ||
| 65 | listPolicies, | ||
| 66 | removePolicy, | ||
| 67 | updatePolicy, | ||
| 68 | } from "@executor/platform-sdk/policies/operations"; | ||
| 69 | import { | 76 | import { |
| 70 | CreateWorkspaceOauthClientPayloadSchema, | 77 | CreateWorkspaceOauthClientPayloadSchema, |
| 71 | DiscoverSourcePayloadSchema, | 78 | DiscoverSourcePayloadSchema, |
| 72 | type CreateWorkspaceOauthClientPayload, | 79 | type CreateWorkspaceOauthClientPayload, |
| 73 | UpdateSourcePayloadSchema, | 80 | UpdateSourcePayloadSchema, |
| 74 | } from "@executor/platform-sdk/sources/contracts"; | 81 | } from "@executor/platform-sdk/contracts"; |
| 75 | import { | ||
| 76 | discoverSource, | ||
| 77 | } from "@executor/platform-sdk/sources/discovery"; | ||
| 78 | import { | ||
| 79 | discoverSourceInspectionTools, | ||
| 80 | getSourceInspection, | ||
| 81 | getSourceInspectionToolDetail, | ||
| 82 | } from "@executor/platform-sdk/sources/inspection"; | ||
| 83 | import { | ||
| 84 | getSource, | ||
| 85 | listSources, | ||
| 86 | removeSource, | ||
| 87 | updateSource, | ||
| 88 | } from "@executor/platform-sdk/sources/operations"; | ||
| 89 | 82 | ||
| 90 | const emptyInputSchema = Schema.standardSchemaV1(Schema.Struct({})); | 83 | const emptyInputSchema = Schema.standardSchemaV1(Schema.Struct({})); |
| 91 | const localInstallationOutputSchema = Schema.standardSchemaV1( | 84 | const localInstallationOutputSchema = Schema.standardSchemaV1( |
| @@ -260,7 +253,7 @@ const runWorkspaceStorageEffect = <A, E, R>(input: { · 168 unmodified lines | |||
| 260 | ) as Effect.Effect<A, E, never>, | 253 | ) as Effect.Effect<A, E, never>, |
| 261 | ); | 254 | ); |
| 262 | 255 | ||
| 263 | export const createExecutorAdminToolMap = ( | 256 | export const createWorkspaceExecutorAdminToolMap = ( |
| 264 | input: WorkspaceInternalToolContext, | 257 | input: WorkspaceInternalToolContext, |
| 265 | ): ToolMap => { | 258 | ): ToolMap => { |
| 266 | const runtimeLayer = makeRuntimeLayer({ | 259 | const runtimeLayer = makeRuntimeLayer({ |
| @@ -690,3 +683,293 @@ export const createExecutorAdminToolMap = ( · 423 unmodified lines | |||
| 690 | }), | 683 | }), |
| 691 | }; | 684 | }; |
| 692 | }; | 685 | }; |
| 686 | |||
| 687 | export const createExecutorAdminToolMap = (input: { | ||
| 688 | executor: Executor; | ||
| 689 | }): ToolMap => { | ||
| 690 | const metadata = { | ||
| 691 | sourceKey: "executor", | ||
| 692 | interaction: "auto" as const, | ||
| 693 | }; | ||
| 694 | |||
| 695 | return { | ||
| 696 | "executor.local.installation.get": toTool({ | ||
| 697 | tool: { | ||
| 698 | description: | ||
| 699 | "Get the active local executor installation account and workspace ids.", | ||
| 700 | inputSchema: emptyInputSchema, | ||
| 701 | outputSchema: localInstallationOutputSchema, | ||
| 702 | execute: () => Promise.resolve(input.executor.installation), | ||
| 703 | }, | ||
| 704 | metadata, | ||
| 705 | }), | ||
| 706 | "executor.local.config.get": toTool({ | ||
| 707 | tool: { | ||
| 708 | description: | ||
| 709 | "Get local instance config such as supported secret providers.", | ||
| 710 | inputSchema: emptyInputSchema, | ||
| 711 | outputSchema: instanceConfigOutputSchema, | ||
| 712 | execute: () => input.executor.local.config(), | ||
| 713 | }, | ||
| 714 | metadata, | ||
| 715 | }), | ||
| 716 | "executor.secrets.list": toTool({ | ||
| 717 | tool: { | ||
| 718 | description: | ||
| 719 | "List locally stored secrets and the sources linked to them.", | ||
| 720 | inputSchema: emptyInputSchema, | ||
| 721 | outputSchema: secretListOutputSchema, | ||
| 722 | execute: () => input.executor.secrets.list(), | ||
| 723 | }, | ||
| 724 | metadata, | ||
| 725 | }), | ||
| 726 | "executor.secrets.create": toTool({ | ||
| 727 | tool: { | ||
| 728 | description: | ||
| 729 | "Create a local secret without putting the raw value into source config.", | ||
| 730 | inputSchema: createSecretInputSchema, | ||
| 731 | outputSchema: Schema.standardSchemaV1(CreateSecretResultSchema), | ||
| 732 | execute: (payload: CreateSecretPayload) => | ||
| 733 | input.executor.secrets.create(payload), | ||
| 734 | }, | ||
| 735 | metadata, | ||
| 736 | }), | ||
| 737 | "executor.secrets.update": toTool({ | ||
| 738 | tool: { | ||
| 739 | description: | ||
| 740 | "Update a stored secret name and optionally rotate its value.", | ||
| 741 | inputSchema: updateSecretInputSchema, | ||
| 742 | outputSchema: Schema.standardSchemaV1(UpdateSecretResultSchema), | ||
| 743 | execute: (payload: { | ||
| 744 | secretId: string; | ||
| 745 | payload: UpdateSecretPayload; | ||
| 746 | }) => input.executor.secrets.update(payload), | ||
| 747 | }, | ||
| 748 | metadata, | ||
| 749 | }), | ||
| 750 | "executor.secrets.remove": toTool({ | ||
| 751 | tool: { | ||
| 752 | description: "Remove a stored local secret.", | ||
| 753 | inputSchema: removeSecretInputSchema, | ||
| 754 | outputSchema: Schema.standardSchemaV1(DeleteSecretResultSchema), | ||
| 755 | execute: ({ secretId }: { secretId: string }) => | ||
| 756 | input.executor.secrets.remove(secretId), | ||
| 757 | }, | ||
| 758 | metadata, | ||
| 759 | }), | ||
| 760 | "executor.sources.discover": toTool({ | ||
| 761 | tool: { | ||
| 762 | description: | ||
| 763 | "Probe a URL and infer whether it looks like MCP, OpenAPI, GraphQL, or another supported source.", | ||
| 764 | inputSchema: discoverSourceInputSchema, | ||
| 765 | outputSchema: sourceDiscoveryOutputSchema, | ||
| 766 | execute: (payload: { url: string; probeAuth?: unknown }) => | ||
| 767 | input.executor.sources.discover({ | ||
| 768 | url: payload.url, | ||
| 769 | probeAuth: payload.probeAuth as never, | ||
| 770 | }), | ||
| 771 | }, | ||
| 772 | metadata, | ||
| 773 | }), | ||
| 774 | "executor.sources.list": toTool({ | ||
| 775 | tool: { | ||
| 776 | description: "List sources connected in the current workspace.", | ||
| 777 | inputSchema: emptyInputSchema, | ||
| 778 | outputSchema: listSourcesOutputSchema, | ||
| 779 | execute: () => input.executor.sources.list(), | ||
| 780 | }, | ||
| 781 | metadata, | ||
| 782 | }), | ||
| 783 | "executor.sources.get": toTool({ | ||
| 784 | tool: { | ||
| 785 | description: "Get one source by id.", | ||
| 786 | inputSchema: getSourceInputSchema, | ||
| 787 | outputSchema: sourceOutputSchema, | ||
| 788 | execute: ({ sourceId }: { sourceId: string }) => | ||
| 789 | input.executor.sources.get(sourceId as never), | ||
| 790 | }, | ||
| 791 | metadata, | ||
| 792 | }), | ||
| 793 | "executor.sources.update": toTool({ | ||
| 794 | tool: { | ||
| 795 | description: "Update a source definition in the current workspace.", | ||
| 796 | inputSchema: updateSourceInputSchema, | ||
| 797 | outputSchema: sourceOutputSchema, | ||
| 798 | execute: (payload: { | ||
| 799 | sourceId: string; | ||
| 800 | payload: Record<string, unknown>; | ||
| 801 | }) => | ||
| 802 | input.executor.sources.update( | ||
| 803 | payload.sourceId as never, | ||
| 804 | payload.payload as never, | ||
| 805 | ), | ||
| 806 | }, | ||
| 807 | metadata, | ||
| 808 | }), | ||
| 809 | "executor.sources.remove": toTool({ | ||
| 810 | tool: { | ||
| 811 | description: "Remove a source from the current workspace.", | ||
| 812 | inputSchema: getSourceInputSchema, | ||
| 813 | outputSchema: removeResultSchema, | ||
| 814 | execute: async ({ sourceId }: { sourceId: string }) => ({ | ||
| 815 | removed: await input.executor.sources.remove(sourceId as never), | ||
| 816 | }), | ||
| 817 | }, | ||
| 818 | metadata, | ||
| 819 | }), | ||
| 820 | "executor.sources.inspect.get": toTool({ | ||
| 821 | tool: { | ||
| 822 | description: "Inspect the tool model for one connected source.", | ||
| 823 | inputSchema: getSourceInputSchema, | ||
| 824 | outputSchema: sourceInspectionOutputSchema, | ||
| 825 | execute: ({ sourceId }: { sourceId: string }) => | ||
| 826 | input.executor.sources.inspection.get(sourceId as never), | ||
| 827 | }, | ||
| 828 | metadata, | ||
| 829 | }), | ||
| 830 | "executor.sources.inspect.tool": toTool({ | ||
| 831 | tool: { | ||
| 832 | description: "Inspect one tool inside a connected source.", | ||
| 833 | inputSchema: inspectToolInputSchema, | ||
| 834 | outputSchema: sourceInspectionToolOutputSchema, | ||
| 835 | execute: ({ | ||
| 836 | sourceId, | ||
| 837 | toolPath, | ||
| 838 | }: { | ||
| 839 | sourceId: string; | ||
| 840 | toolPath: string; | ||
| 841 | }) => | ||
| 842 | input.executor.sources.inspection.tool({ | ||
| 843 | sourceId: sourceId as never, | ||
| 844 | toolPath, | ||
| 845 | }), | ||
| 846 | }, | ||
| 847 | metadata, | ||
| 848 | }), | ||
| 849 | "executor.sources.inspect.discover": toTool({ | ||
| 850 | tool: { | ||
| 851 | description: "Search within a single source's inspected tools.", | ||
| 852 | inputSchema: inspectDiscoverInputSchema, | ||
| 853 | outputSchema: sourceInspectionDiscoverOutputSchema, | ||
| 854 | execute: ({ | ||
| 855 | sourceId, | ||
| 856 | payload, | ||
| 857 | }: { | ||
| 858 | sourceId: string; | ||
| 859 | payload: { query: string; limit?: number }; | ||
| 860 | }) => | ||
| 861 | input.executor.sources.inspection.discover({ | ||
| 862 | sourceId: sourceId as never, | ||
| 863 | payload: payload as never, | ||
| 864 | }), | ||
| 865 | }, | ||
| 866 | metadata, | ||
| 867 | }), | ||
| 868 | "executor.sources.oauthClients.list": toTool({ | ||
| 869 | tool: { | ||
| 870 | description: "List stored workspace OAuth clients for one provider.", | ||
| 871 | inputSchema: workspaceOauthClientListInputSchema, | ||
| 872 | outputSchema: workspaceOauthClientListOutputSchema, | ||
| 873 | execute: ({ providerKey }: { providerKey: string }) => | ||
| 874 | input.executor.sources.oauthClients.list(providerKey), | ||
| 875 | }, | ||
| 876 | metadata, | ||
| 877 | }), | ||
| 878 | "executor.sources.oauthClients.create": toTool({ | ||
| 879 | tool: { | ||
| 880 | description: | ||
| 881 | "Create a workspace OAuth client for a provider-backed source flow.", | ||
| 882 | inputSchema: createWorkspaceOauthClientInputSchema, | ||
| 883 | outputSchema: Schema.standardSchemaV1(WorkspaceOauthClientSchema), | ||
| 884 | execute: (payload: CreateWorkspaceOauthClientPayload) => | ||
| 885 | input.executor.sources.oauthClients.create(payload), | ||
| 886 | }, | ||
| 887 | metadata, | ||
| 888 | }), | ||
| 889 | "executor.sources.oauthClients.remove": toTool({ | ||
| 890 | tool: { | ||
| 891 | description: "Remove a stored workspace OAuth client.", | ||
| 892 | inputSchema: removeWorkspaceOauthClientInputSchema, | ||
| 893 | outputSchema: removeResultSchema, | ||
| 894 | execute: async ({ | ||
| 895 | oauthClientId, | ||
| 896 | }: { | ||
| 897 | oauthClientId: string; | ||
| 898 | }) => ({ | ||
| 899 | removed: await input.executor.sources.oauthClients.remove( | ||
| 900 | oauthClientId as never, | ||
| 901 | ), | ||
| 902 | }), | ||
| 903 | }, | ||
| 904 | metadata, | ||
| 905 | }), | ||
| 906 | "executor.sources.providerGrants.remove": toTool({ | ||
| 907 | tool: { | ||
| 908 | description: "Remove one stored provider auth grant.", | ||
| 909 | inputSchema: removeProviderGrantInputSchema, | ||
| 910 | outputSchema: removeResultSchema, | ||
| 911 | execute: async ({ grantId }: { grantId: string }) => ({ | ||
| 912 | removed: await input.executor.sources.providerGrants.remove( | ||
| 913 | grantId as never, | ||
| 914 | ), | ||
| 915 | }), | ||
| 916 | }, | ||
| 917 | metadata, | ||
| 918 | }), | ||
| 919 | "executor.policies.list": toTool({ | ||
| 920 | tool: { | ||
| 921 | description: "List local workspace policies.", | ||
| 922 | inputSchema: emptyInputSchema, | ||
| 923 | outputSchema: listPoliciesOutputSchema, | ||
| 924 | execute: () => input.executor.policies.list(), | ||
| 925 | }, | ||
| 926 | metadata, | ||
| 927 | }), | ||
| 928 | "executor.policies.create": toTool({ | ||
| 929 | tool: { | ||
| 930 | description: "Create a local workspace policy.", | ||
| 931 | inputSchema: createPolicyInputSchema, | ||
| 932 | outputSchema: localWorkspacePolicyOutputSchema, | ||
| 933 | execute: (payload: CreatePolicyPayload) => | ||
| 934 | input.executor.policies.create(payload), | ||
| 935 | }, | ||
| 936 | metadata, | ||
| 937 | }), | ||
| 938 | "executor.policies.get": toTool({ | ||
| 939 | tool: { | ||
| 940 | description: "Get one local workspace policy by id.", | ||
| 941 | inputSchema: policyIdInputSchema, | ||
| 942 | outputSchema: localWorkspacePolicyOutputSchema, | ||
| 943 | execute: ({ policyId }: { policyId: string }) => | ||
| 944 | input.executor.policies.get(policyId), | ||
| 945 | }, | ||
| 946 | metadata, | ||
| 947 | }), | ||
| 948 | "executor.policies.update": toTool({ | ||
| 949 | tool: { | ||
| 950 | description: "Update a local workspace policy.", | ||
| 951 | inputSchema: updatePolicyInputSchema, | ||
| 952 | outputSchema: localWorkspacePolicyOutputSchema, | ||
| 953 | execute: ({ | ||
| 954 | policyId, | ||
| 955 | payload, | ||
| 956 | }: { | ||
| 957 | policyId: string; | ||
| 958 | payload: UpdatePolicyPayload; | ||
| 959 | }) => input.executor.policies.update(policyId, payload), | ||
| 960 | }, | ||
| 961 | metadata, | ||
| 962 | }), | ||
| 963 | "executor.policies.remove": toTool({ | ||
| 964 | tool: { | ||
| 965 | description: "Remove a local workspace policy.", | ||
| 966 | inputSchema: policyIdInputSchema, | ||
| 967 | outputSchema: removeResultSchema, | ||
| 968 | execute: async ({ policyId }: { policyId: string }) => ({ | ||
| 969 | removed: await input.executor.policies.remove(policyId), | ||
| 970 | }), | ||
| 971 | }, | ||
| 972 | metadata, | ||
| 973 | }), | ||
| 974 | }; | ||
| 975 | }; | ||
| @@ -4,20 +4,14 @@ · 3 unmodified lines | |||
| 4 | "type": "module", | 4 | "type": "module", |
| 5 | "exports": { | 5 | "exports": { |
| 6 | ".": "./src/index.ts", | 6 | ".": "./src/index.ts", |
| 7 | "./backend": "./src/backend.ts", | ||
| 8 | "./contracts": "./src/contracts.ts", | ||
| 9 | "./executor": "./src/executor.ts", | ||
| 7 | "./errors": "./src/errors.ts", | 10 | "./errors": "./src/errors.ts", |
| 11 | "./operations": "./src/operations.ts", | ||
| 8 | "./string-schemas": "./src/string-schemas.ts", | 12 | "./string-schemas": "./src/string-schemas.ts", |
| 9 | "./executions/contracts": "./src/executions/contracts.ts", | ||
| 10 | "./schema": "./src/schema/index.ts", | 13 | "./schema": "./src/schema/index.ts", |
| 11 | "./runtime": "./src/runtime/index.ts", | 14 | "./runtime": "./src/runtime/index.ts" |
| 12 | "./local/contracts": "./src/local/contracts.ts", | ||
| 13 | "./local/operations": "./src/local/operations.ts", | ||
| 14 | "./local/secrets": "./src/local/secrets.ts", | ||
| 15 | "./policies/contracts": "./src/policies/contracts.ts", | ||
| 16 | "./policies/operations": "./src/policies/operations.ts", | ||
| 17 | "./sources/contracts": "./src/sources/contracts.ts", | ||
| 18 | "./sources/discovery": "./src/sources/discovery.ts", | ||
| 19 | "./sources/inspection": "./src/sources/inspection.ts", | ||
| 20 | "./sources/operations": "./src/sources/operations.ts" | ||
| 21 | }, | 15 | }, |
| 22 | "imports": { | 16 | "imports": { |
| 23 | "#runtime": "./src/runtime/index.ts", | 17 | "#runtime": "./src/runtime/index.ts", |
| @@ -0,0 +1,42 @@ | |||
| 1 | import * as Effect from "effect/Effect"; | ||
| 2 | |||
| 3 | import { | ||
| 4 | createControlPlaneRuntimeFromServices, | ||
| 5 | type BoundInstallationStore, | ||
| 6 | type BoundLocalToolRuntimeLoader, | ||
| 7 | type BoundSourceArtifactStore, | ||
| 8 | type BoundWorkspaceConfigStore, | ||
| 9 | type BoundWorkspaceStateStore, | ||
| 10 | type ControlPlaneRuntime, | ||
| 11 | type RuntimeControlPlaneOptions, | ||
| 12 | type RuntimeControlPlaneServices, | ||
| 13 | type RuntimeSecretMaterialServices, | ||
| 14 | } from "./runtime"; | ||
| 15 | |||
| 16 | export type ExecutorBackend = { | ||
| 17 | createRuntime: ( | ||
| 18 | options: RuntimeControlPlaneOptions, | ||
| 19 | ) => Effect.Effect<ControlPlaneRuntime, Error>; | ||
| 20 | }; | ||
| 21 | |||
| 22 | export type ExecutorBackendServices = RuntimeControlPlaneServices; | ||
| 23 | export type ExecutorInstallationBackend = BoundInstallationStore; | ||
| 24 | export type ExecutorWorkspaceConfigBackend = BoundWorkspaceConfigStore; | ||
| 25 | export type ExecutorWorkspaceStateBackend = BoundWorkspaceStateStore; | ||
| 26 | export type ExecutorSourceArtifactBackend = BoundSourceArtifactStore; | ||
| 27 | export type ExecutorLocalToolBackend = BoundLocalToolRuntimeLoader; | ||
| 28 | export type ExecutorSecretMaterialBackend = RuntimeSecretMaterialServices; | ||
| 29 | |||
| 30 | export const createExecutorBackend = (input: { | ||
| 31 | loadServices: ( | ||
| 32 | options: RuntimeControlPlaneOptions, | ||
| 33 | ) => Effect.Effect<ExecutorBackendServices, Error>; | ||
| 34 | }): ExecutorBackend => ({ | ||
| 35 | createRuntime: (options) => | ||
| 36 | Effect.flatMap(input.loadServices(options), (services) => | ||
| 37 | createControlPlaneRuntimeFromServices({ | ||
| 38 | ...options, | ||
| 39 | services, | ||
| 40 | }), | ||
| 41 | ), | ||
| 42 | }); | ||
| @@ -0,0 +1,4 @@ | |||
| 1 | export * from "./executions/contracts"; | ||
| 2 | export * from "./local/contracts"; | ||
| 3 | export * from "./policies/contracts"; | ||
| 4 | export * from "./sources/contracts"; | ||
| @@ -0,0 +1,694 @@ | |||
| 1 | import * as Effect from "effect/Effect"; | ||
| 2 | |||
| 3 | import type { | ||
| 4 | AccountId, | ||
| 5 | Execution, | ||
| 6 | ExecutionEnvelope, | ||
| 7 | ExecutionInteraction, | ||
| 8 | LocalInstallation, | ||
| 9 | LocalWorkspacePolicy, | ||
| 10 | ProviderAuthGrant, | ||
| 11 | Source, | ||
| 12 | WorkspaceId, | ||
| 13 | WorkspaceOauthClient, | ||
| 14 | } from "./schema"; | ||
| 15 | import { ExecutionIdSchema } from "./schema"; | ||
| 16 | import type { CreateExecutionPayload, ResumeExecutionPayload } from "./executions/contracts"; | ||
| 17 | import type { | ||
| 18 | CreateSecretPayload, | ||
| 19 | CreateSecretResult, | ||
| 20 | DeleteSecretResult, | ||
| 21 | InstanceConfig, | ||
| 22 | SecretListItem, | ||
| 23 | UpdateSecretPayload, | ||
| 24 | UpdateSecretResult, | ||
| 25 | } from "./local/contracts"; | ||
| 26 | import { | ||
| 27 | completeSourceCredentialSetup, | ||
| 28 | getLocalInstallation, | ||
| 29 | getSourceCredentialInteraction, | ||
| 30 | submitSourceCredentialInteraction, | ||
| 31 | } from "./local/operations"; | ||
| 32 | import { | ||
| 33 | createLocalSecret, | ||
| 34 | deleteLocalSecret, | ||
| 35 | getLocalInstanceConfig, | ||
| 36 | listLocalSecrets, | ||
| 37 | updateLocalSecret, | ||
| 38 | } from "./local/secrets"; | ||
| 39 | import type { CreatePolicyPayload, UpdatePolicyPayload } from "./policies/contracts"; | ||
| 40 | import { | ||
| 41 | createPolicy, | ||
| 42 | getPolicy, | ||
| 43 | listPolicies, | ||
| 44 | removePolicy, | ||
| 45 | updatePolicy, | ||
| 46 | } from "./policies/operations"; | ||
| 47 | import type { | ||
| 48 | CreateSourcePayload, | ||
| 49 | CreateWorkspaceOauthClientPayload, | ||
| 50 | UpdateSourcePayload, | ||
| 51 | } from "./sources/contracts"; | ||
| 52 | import { discoverSource } from "./sources/discovery"; | ||
| 53 | import { | ||
| 54 | discoverSourceInspectionTools, | ||
| 55 | getSourceInspection, | ||
| 56 | getSourceInspectionToolDetail, | ||
| 57 | } from "./sources/inspection"; | ||
| 58 | import { | ||
| 59 | createSource, | ||
| 60 | getSource, | ||
| 61 | listSources, | ||
| 62 | removeSource, | ||
| 63 | updateSource, | ||
| 64 | } from "./sources/operations"; | ||
| 65 | import type { ExecutorBackend } from "./backend"; | ||
| 66 | import { | ||
| 67 | provideControlPlaneRuntime, | ||
| 68 | type ControlPlaneRuntime, | ||
| 69 | type CreateWorkspaceInternalToolMap, | ||
| 70 | type ResolveExecutionEnvironment, | ||
| 71 | type ResolveSecretMaterial, | ||
| 72 | RuntimeSourceAuthServiceTag, | ||
| 73 | } from "./runtime"; | ||
| 74 | import { createExecution, getExecution, resumeExecution } from "./runtime/execution/service"; | ||
| 75 | import type { | ||
| 76 | CompleteProviderOauthCallbackResult, | ||
| 77 | CompleteSourceCredentialSetupResult, | ||
| 78 | CompleteSourceOAuthSessionResult, | ||
| 79 | ConnectGoogleDiscoveryBatchInput, | ||
| 80 | ConnectGoogleDiscoveryBatchResult, | ||
| 81 | ConnectMcpSourceInput, | ||
| 82 | ExecutorAddSourceInput, | ||
| 83 | ExecutorSourceAddResult, | ||
| 84 | McpSourceConnectResult, | ||
| 85 | StartSourceOAuthSessionInput, | ||
| 86 | StartSourceOAuthSessionResult, | ||
| 87 | } from "./runtime/sources/source-auth-service"; | ||
| 88 | |||
| 89 | export type ExecutorRuntimeOptions = { | ||
| 90 | executionResolver?: ResolveExecutionEnvironment; | ||
| 91 | createInternalToolMap?: CreateWorkspaceInternalToolMap; | ||
| 92 | resolveSecretMaterial?: ResolveSecretMaterial; | ||
| 93 | getLocalServerBaseUrl?: () => string | undefined; | ||
| 94 | }; | ||
| 95 | |||
| 96 | type DistributiveOmit<T, Keys extends PropertyKey> = T extends unknown ? Omit<T, Keys> : never; | ||
| 97 | type ProvidedEffect<T extends Effect.Effect<any, any, any>> = Effect.Effect< | ||
| 98 | Effect.Effect.Success<T>, | ||
| 99 | Effect.Effect.Error<T>, | ||
| 100 | never | ||
| 101 | >; | ||
| 102 | |||
| 103 | export type ExecutorSourceInput = DistributiveOmit< | ||
| 104 | ExecutorAddSourceInput, | ||
| 105 | "workspaceId" | "actorAccountId" | "executionId" | "interactionId" | ||
| 106 | >; | ||
| 107 | |||
| 108 | export type ExecutorSourceBatchInput = DistributiveOmit< | ||
| 109 | ConnectGoogleDiscoveryBatchInput, | ||
| 110 | "workspaceId" | "actorAccountId" | "executionId" | "interactionId" | ||
| 111 | >; | ||
| 112 | |||
| 113 | export type ExecutorMcpSourceInput = DistributiveOmit< | ||
| 114 | ConnectMcpSourceInput, | ||
| 115 | "workspaceId" | "actorAccountId" | ||
| 116 | >; | ||
| 117 | |||
| 118 | export type ExecutorSourceOAuthInput = DistributiveOmit< | ||
| 119 | StartSourceOAuthSessionInput, | ||
| 120 | "workspaceId" | "actorAccountId" | ||
| 121 | >; | ||
| 122 | |||
| 123 | export type Executor = { | ||
| 124 | runtime: ControlPlaneRuntime; | ||
| 125 | installation: LocalInstallation; | ||
| 126 | workspaceId: WorkspaceId; | ||
| 127 | accountId: AccountId; | ||
| 128 | provide: <A, E, R>(effect: Effect.Effect<A, E, R>) => Effect.Effect<A, E, any>; | ||
| 129 | run: <A, E, R>(effect: Effect.Effect<A, E, R>) => Promise<A>; | ||
| 130 | close: () => Promise<void>; | ||
| 131 | effect: { | ||
| 132 | local: { | ||
| 133 | installation: () => ProvidedEffect<ReturnType<typeof getLocalInstallation>>; | ||
| 134 | config: () => ProvidedEffect<ReturnType<typeof getLocalInstanceConfig>>; | ||
| 135 | credentials: { | ||
| 136 | get: (input: { | ||
| 137 | sourceId: Source["id"]; | ||
| 138 | interactionId: ExecutionInteraction["id"]; | ||
| 139 | }) => ProvidedEffect<ReturnType<typeof getSourceCredentialInteraction>>; | ||
| 140 | submit: (input: { | ||
| 141 | sourceId: Source["id"]; | ||
| 142 | interactionId: ExecutionInteraction["id"]; | ||
| 143 | action: "submit" | "continue" | "cancel"; | ||
| 144 | token?: string | null; | ||
| 145 | }) => ProvidedEffect<ReturnType<typeof submitSourceCredentialInteraction>>; | ||
| 146 | complete: (input: { | ||
| 147 | sourceId: Source["id"]; | ||
| 148 | state: string; | ||
| 149 | code?: string | null; | ||
| 150 | error?: string | null; | ||
| 151 | errorDescription?: string | null; | ||
| 152 | }) => ProvidedEffect<ReturnType<typeof completeSourceCredentialSetup>>; | ||
| 153 | }; | ||
| 154 | }; | ||
| 155 | secrets: { | ||
| 156 | list: () => ProvidedEffect<ReturnType<typeof listLocalSecrets>>; | ||
| 157 | create: (payload: CreateSecretPayload) => ProvidedEffect<ReturnType<typeof createLocalSecret>>; | ||
| 158 | update: (input: { | ||
| 159 | secretId: string; | ||
| 160 | payload: UpdateSecretPayload; | ||
| 161 | }) => ProvidedEffect<ReturnType<typeof updateLocalSecret>>; | ||
| 162 | remove: (secretId: string) => ProvidedEffect<ReturnType<typeof deleteLocalSecret>>; | ||
| 163 | }; | ||
| 164 | policies: { | ||
| 165 | list: () => ProvidedEffect<ReturnType<typeof listPolicies>>; | ||
| 166 | create: (payload: CreatePolicyPayload) => ProvidedEffect<ReturnType<typeof createPolicy>>; | ||
| 167 | get: (policyId: string) => ProvidedEffect<ReturnType<typeof getPolicy>>; | ||
| 168 | update: ( | ||
| 169 | policyId: string, | ||
| 170 | payload: UpdatePolicyPayload, | ||
| 171 | ) => ProvidedEffect<ReturnType<typeof updatePolicy>>; | ||
| 172 | remove: (policyId: string) => ProvidedEffect<ReturnType<typeof removePolicy>>; | ||
| 173 | }; | ||
| 174 | sources: { | ||
| 175 | add: ( | ||
| 176 | input: ExecutorSourceInput, | ||
| 177 | options?: { | ||
| 178 | baseUrl?: string | null; | ||
| 179 | }, | ||
| 180 | ) => Effect.Effect<ExecutorSourceAddResult, Error, never>; | ||
| 181 | connect: (payload: ExecutorMcpSourceInput) => Effect.Effect<McpSourceConnectResult, Error, never>; | ||
| 182 | connectBatch: ( | ||
| 183 | payload: ExecutorSourceBatchInput, | ||
| 184 | ) => Effect.Effect<ConnectGoogleDiscoveryBatchResult, Error, never>; | ||
| 185 | discover: (input: { | ||
| 186 | url: string; | ||
| 187 | probeAuth?: Parameters<typeof discoverSource>[0]["probeAuth"]; | ||
| 188 | }) => ProvidedEffect<ReturnType<typeof discoverSource>>; | ||
| 189 | list: () => ProvidedEffect<ReturnType<typeof listSources>>; | ||
| 190 | create: (payload: CreateSourcePayload) => ProvidedEffect<ReturnType<typeof createSource>>; | ||
| 191 | get: (sourceId: Source["id"]) => ProvidedEffect<ReturnType<typeof getSource>>; | ||
| 192 | update: ( | ||
| 193 | sourceId: Source["id"], | ||
| 194 | payload: UpdateSourcePayload, | ||
| 195 | ) => ProvidedEffect<ReturnType<typeof updateSource>>; | ||
| 196 | remove: (sourceId: Source["id"]) => ProvidedEffect<ReturnType<typeof removeSource>>; | ||
| 197 | inspection: { | ||
| 198 | get: (sourceId: Source["id"]) => ProvidedEffect<ReturnType<typeof getSourceInspection>>; | ||
| 199 | tool: (input: { | ||
| 200 | sourceId: Source["id"]; | ||
| 201 | toolPath: string; | ||
| 202 | }) => ProvidedEffect<ReturnType<typeof getSourceInspectionToolDetail>>; | ||
| 203 | discover: (input: { | ||
| 204 | sourceId: Source["id"]; | ||
| 205 | payload: Parameters<typeof discoverSourceInspectionTools>[0]["payload"]; | ||
| 206 | }) => ProvidedEffect<ReturnType<typeof discoverSourceInspectionTools>>; | ||
| 207 | }; | ||
| 208 | oauthClients: { | ||
| 209 | list: ( | ||
| 210 | providerKey: string, | ||
| 211 | ) => Effect.Effect<ReadonlyArray<WorkspaceOauthClient>, Error, never>; | ||
| 212 | create: ( | ||
| 213 | payload: CreateWorkspaceOauthClientPayload, | ||
| 214 | ) => Effect.Effect<WorkspaceOauthClient, Error, never>; | ||
| 215 | remove: ( | ||
| 216 | oauthClientId: WorkspaceOauthClient["id"], | ||
| 217 | ) => Effect.Effect<boolean, Error, never>; | ||
| 218 | }; | ||
| 219 | providerGrants: { | ||
| 220 | remove: (grantId: ProviderAuthGrant["id"]) => Effect.Effect<boolean, Error, never>; | ||
| 221 | }; | ||
| 222 | }; | ||
| 223 | oauth: { | ||
| 224 | startSourceAuth: ( | ||
| 225 | input: ExecutorSourceOAuthInput, | ||
| 226 | ) => Effect.Effect<StartSourceOAuthSessionResult, Error, never>; | ||
| 227 | completeSourceAuth: (input: { | ||
| 228 | state: string; | ||
| 229 | code?: string | null; | ||
| 230 | error?: string | null; | ||
| 231 | errorDescription?: string | null; | ||
| 232 | }) => Effect.Effect<CompleteSourceOAuthSessionResult, Error, never>; | ||
| 233 | completeProviderCallback: (input: { | ||
| 234 | workspaceId?: WorkspaceId; | ||
| 235 | actorAccountId?: AccountId | null; | ||
| 236 | state: string; | ||
| 237 | code?: string | null; | ||
| 238 | error?: string | null; | ||
| 239 | errorDescription?: string | null; | ||
| 240 | }) => Effect.Effect<CompleteProviderOauthCallbackResult, Error, never>; | ||
| 241 | }; | ||
| 242 | executions: { | ||
| 243 | create: (payload: CreateExecutionPayload) => ProvidedEffect<ReturnType<typeof createExecution>>; | ||
| 244 | get: (executionId: Execution["id"]) => ProvidedEffect<ReturnType<typeof getExecution>>; | ||
| 245 | resume: ( | ||
| 246 | executionId: Execution["id"], | ||
| 247 | payload: ResumeExecutionPayload, | ||
| 248 | ) => ProvidedEffect<ReturnType<typeof resumeExecution>>; | ||
| 249 | }; | ||
| 250 | }; | ||
| 251 | local: { | ||
| 252 | installation: () => Promise<LocalInstallation>; | ||
| 253 | config: () => Promise<InstanceConfig>; | ||
| 254 | credentials: { | ||
| 255 | get: (input: { | ||
| 256 | sourceId: Source["id"]; | ||
| 257 | interactionId: ExecutionInteraction["id"]; | ||
| 258 | }) => Promise<Effect.Effect.Success<ReturnType<typeof getSourceCredentialInteraction>>>; | ||
| 259 | submit: (input: { | ||
| 260 | sourceId: Source["id"]; | ||
| 261 | interactionId: ExecutionInteraction["id"]; | ||
| 262 | action: "submit" | "continue" | "cancel"; | ||
| 263 | token?: string | null; | ||
| 264 | }) => Promise<Effect.Effect.Success<ReturnType<typeof submitSourceCredentialInteraction>>>; | ||
| 265 | complete: (input: { | ||
| 266 | sourceId: Source["id"]; | ||
| 267 | state: string; | ||
| 268 | code?: string | null; | ||
| 269 | error?: string | null; | ||
| 270 | errorDescription?: string | null; | ||
| 271 | }) => Promise<CompleteSourceCredentialSetupResult>; | ||
| 272 | }; | ||
| 273 | }; | ||
| 274 | secrets: { | ||
| 275 | list: () => Promise<ReadonlyArray<SecretListItem>>; | ||
| 276 | create: (payload: CreateSecretPayload) => Promise<CreateSecretResult>; | ||
| 277 | update: (input: { | ||
| 278 | secretId: string; | ||
| 279 | payload: UpdateSecretPayload; | ||
| 280 | }) => Promise<UpdateSecretResult>; | ||
| 281 | remove: (secretId: string) => Promise<DeleteSecretResult>; | ||
| 282 | }; | ||
| 283 | policies: { | ||
| 284 | list: () => Promise<ReadonlyArray<LocalWorkspacePolicy>>; | ||
| 285 | create: (payload: CreatePolicyPayload) => Promise<LocalWorkspacePolicy>; | ||
| 286 | get: (policyId: string) => Promise<LocalWorkspacePolicy>; | ||
| 287 | update: ( | ||
| 288 | policyId: string, | ||
| 289 | payload: UpdatePolicyPayload, | ||
| 290 | ) => Promise<LocalWorkspacePolicy>; | ||
| 291 | remove: (policyId: string) => Promise<boolean>; | ||
| 292 | }; | ||
| 293 | sources: { | ||
| 294 | add: ( | ||
| 295 | input: ExecutorSourceInput, | ||
| 296 | options?: { | ||
| 297 | baseUrl?: string | null; | ||
| 298 | }, | ||
| 299 | ) => Promise<ExecutorSourceAddResult>; | ||
| 300 | connect: (payload: ExecutorMcpSourceInput) => Promise<McpSourceConnectResult>; | ||
| 301 | connectBatch: (payload: ExecutorSourceBatchInput) => Promise<ConnectGoogleDiscoveryBatchResult>; | ||
| 302 | discover: (input: { | ||
| 303 | url: string; | ||
| 304 | probeAuth?: Parameters<typeof discoverSource>[0]["probeAuth"]; | ||
| 305 | }) => Promise<Effect.Effect.Success<ReturnType<typeof discoverSource>>>; | ||
| 306 | list: () => Promise<ReadonlyArray<Source>>; | ||
| 307 | create: (payload: CreateSourcePayload) => Promise<Source>; | ||
| 308 | get: (sourceId: Source["id"]) => Promise<Source>; | ||
| 309 | update: (sourceId: Source["id"], payload: UpdateSourcePayload) => Promise<Source>; | ||
| 310 | remove: (sourceId: Source["id"]) => Promise<boolean>; | ||
| 311 | inspection: { | ||
| 312 | get: (sourceId: Source["id"]) => Promise<Effect.Effect.Success<ReturnType<typeof getSourceInspection>>>; | ||
| 313 | tool: (input: { | ||
| 314 | sourceId: Source["id"]; | ||
| 315 | toolPath: string; | ||
| 316 | }) => Promise<Effect.Effect.Success<ReturnType<typeof getSourceInspectionToolDetail>>>; | ||
| 317 | discover: (input: { | ||
| 318 | sourceId: Source["id"]; | ||
| 319 | payload: Parameters<typeof discoverSourceInspectionTools>[0]["payload"]; | ||
| 320 | }) => Promise<Effect.Effect.Success<ReturnType<typeof discoverSourceInspectionTools>>>; | ||
| 321 | }; | ||
| 322 | oauthClients: { | ||
| 323 | list: (providerKey: string) => Promise<ReadonlyArray<WorkspaceOauthClient>>; | ||
| 324 | create: ( | ||
| 325 | payload: CreateWorkspaceOauthClientPayload, | ||
| 326 | ) => Promise<WorkspaceOauthClient>; | ||
| 327 | remove: (oauthClientId: WorkspaceOauthClient["id"]) => Promise<boolean>; | ||
| 328 | }; | ||
| 329 | providerGrants: { | ||
| 330 | remove: (grantId: ProviderAuthGrant["id"]) => Promise<boolean>; | ||
| 331 | }; | ||
| 332 | }; | ||
| 333 | oauth: { | ||
| 334 | startSourceAuth: (input: ExecutorSourceOAuthInput) => Promise<StartSourceOAuthSessionResult>; | ||
| 335 | completeSourceAuth: (input: { | ||
| 336 | state: string; | ||
| 337 | code?: string | null; | ||
| 338 | error?: string | null; | ||
| 339 | errorDescription?: string | null; | ||
| 340 | }) => Promise<CompleteSourceOAuthSessionResult>; | ||
| 341 | completeProviderCallback: (input: { | ||
| 342 | workspaceId?: WorkspaceId; | ||
| 343 | actorAccountId?: AccountId | null; | ||
| 344 | state: string; | ||
| 345 | code?: string | null; | ||
| 346 | error?: string | null; | ||
| 347 | errorDescription?: string | null; | ||
| 348 | }) => Promise<CompleteProviderOauthCallbackResult>; | ||
| 349 | }; | ||
| 350 | executions: { | ||
| 351 | create: (payload: CreateExecutionPayload) => Promise<ExecutionEnvelope>; | ||
| 352 | get: (executionId: Execution["id"]) => Promise<ExecutionEnvelope>; | ||
| 353 | resume: ( | ||
| 354 | executionId: Execution["id"], | ||
| 355 | payload: ResumeExecutionPayload, | ||
| 356 | ) => Promise<ExecutionEnvelope>; | ||
| 357 | }; | ||
| 358 | }; | ||
| 359 | |||
| 360 | export type CreateExecutorOptions = ExecutorRuntimeOptions & { | ||
| 361 | backend: ExecutorBackend; | ||
| 362 | }; | ||
| 363 | |||
| 364 | const fromRuntime = (runtime: ControlPlaneRuntime): Executor => { | ||
| 365 | const installation = runtime.localInstallation; | ||
| 366 | const workspaceId = installation.workspaceId; | ||
| 367 | const accountId = installation.accountId; | ||
| 368 | const provide = <A, E, R>(effect: Effect.Effect<A, E, R>) => | ||
| 369 | provideControlPlaneRuntime(effect, runtime); | ||
| 370 | const run = <A, E, R>(effect: Effect.Effect<A, E, R>) => | ||
| 371 | Effect.runPromise(provide(effect) as Effect.Effect<A, E, never>); | ||
| 372 | const provideSourceAuth = <A, E>( | ||
| 373 | execute: ( | ||
| 374 | service: Effect.Effect.Success<typeof RuntimeSourceAuthServiceTag>, | ||
| 375 | ) => Effect.Effect<A, E, any>, | ||
| 376 | ) => provide(Effect.flatMap(RuntimeSourceAuthServiceTag, execute)); | ||
| 377 | const createSdkSourceSession = () => { | ||
| 378 | const id = crypto.randomUUID(); | ||
| 379 | return { | ||
| 380 | executionId: ExecutionIdSchema.make(`exec_sdk_${id}`), | ||
| 381 | interactionId: `executor.sdk.${id}` as never, | ||
| 382 | }; | ||
| 383 | }; | ||
| 384 | const effect = { | ||
| 385 | local: { | ||
| 386 | installation: () => provide(getLocalInstallation()), | ||
| 387 | config: () => provide(getLocalInstanceConfig()), | ||
| 388 | credentials: { | ||
| 389 | get: ({ sourceId, interactionId }) => | ||
| 390 | provide( | ||
| 391 | getSourceCredentialInteraction({ | ||
| 392 | workspaceId, | ||
| 393 | sourceId, | ||
| 394 | interactionId, | ||
| 395 | }), | ||
| 396 | ), | ||
| 397 | submit: ({ sourceId, interactionId, action, token }) => | ||
| 398 | provide( | ||
| 399 | submitSourceCredentialInteraction({ | ||
| 400 | workspaceId, | ||
| 401 | sourceId, | ||
| 402 | interactionId, | ||
| 403 | action, | ||
| 404 | token, | ||
| 405 | }), | ||
| 406 | ), | ||
| 407 | complete: ({ sourceId, state, code, error, errorDescription }) => | ||
| 408 | provide( | ||
| 409 | completeSourceCredentialSetup({ | ||
| 410 | workspaceId, | ||
| 411 | sourceId, | ||
| 412 | state, | ||
| 413 | code, | ||
| 414 | error, | ||
| 415 | errorDescription, | ||
| 416 | }), | ||
| 417 | ), | ||
| 418 | }, | ||
| 419 | }, | ||
| 420 | secrets: { | ||
| 421 | list: () => provide(listLocalSecrets()), | ||
| 422 | create: (payload: CreateSecretPayload) => provide(createLocalSecret(payload)), | ||
| 423 | update: (input: { secretId: string; payload: UpdateSecretPayload }) => | ||
| 424 | provide(updateLocalSecret(input)), | ||
| 425 | remove: (secretId: string) => provide(deleteLocalSecret(secretId)), | ||
| 426 | }, | ||
| 427 | policies: { | ||
| 428 | list: () => provide(listPolicies(workspaceId)), | ||
| 429 | create: (payload: CreatePolicyPayload) => | ||
| 430 | provide(createPolicy({ workspaceId, payload })), | ||
| 431 | get: (policyId: string) => | ||
| 432 | provide(getPolicy({ workspaceId, policyId: policyId as never })), | ||
| 433 | update: (policyId: string, payload: UpdatePolicyPayload) => | ||
| 434 | provide(updatePolicy({ workspaceId, policyId: policyId as never, payload })), | ||
| 435 | remove: (policyId: string) => | ||
| 436 | provide(removePolicy({ workspaceId, policyId: policyId as never })), | ||
| 437 | }, | ||
| 438 | sources: { | ||
| 439 | add: (input: ExecutorSourceInput, options?: { baseUrl?: string | null }) => | ||
| 440 | provideSourceAuth((service) => { | ||
| 441 | const session = createSdkSourceSession(); | ||
| 442 | return service.addExecutorSource( | ||
| 443 | { | ||
| 444 | ...input, | ||
| 445 | workspaceId, | ||
| 446 | actorAccountId: accountId, | ||
| 447 | executionId: session.executionId, | ||
| 448 | interactionId: session.interactionId, | ||
| 449 | }, | ||
| 450 | options, | ||
| 451 | ); | ||
| 452 | }), | ||
| 453 | connect: (payload: ExecutorMcpSourceInput) => | ||
| 454 | provideSourceAuth((service) => | ||
| 455 | service.connectMcpSource({ | ||
| 456 | ...payload, | ||
| 457 | workspaceId, | ||
| 458 | actorAccountId: accountId, | ||
| 459 | }), | ||
| 460 | ), | ||
| 461 | connectBatch: (payload: ExecutorSourceBatchInput) => | ||
| 462 | provideSourceAuth((service) => { | ||
| 463 | const session = createSdkSourceSession(); | ||
| 464 | return service.connectGoogleDiscoveryBatch({ | ||
| 465 | ...payload, | ||
| 466 | workspaceId, | ||
| 467 | actorAccountId: accountId, | ||
| 468 | executionId: session.executionId, | ||
| 469 | interactionId: session.interactionId, | ||
| 470 | }); | ||
| 471 | }), | ||
| 472 | discover: (input: { | ||
| 473 | url: string; | ||
| 474 | probeAuth?: Parameters<typeof discoverSource>[0]["probeAuth"]; | ||
| 475 | }) => provide(discoverSource(input)), | ||
| 476 | list: () => provide(listSources({ workspaceId, accountId })), | ||
| 477 | create: (payload: CreateSourcePayload) => | ||
| 478 | provide(createSource({ workspaceId, accountId, payload })), | ||
| 479 | get: (sourceId: Source["id"]) => | ||
| 480 | provide(getSource({ workspaceId, sourceId, accountId })), | ||
| 481 | update: (sourceId: Source["id"], payload: UpdateSourcePayload) => | ||
| 482 | provide(updateSource({ workspaceId, sourceId, accountId, payload })), | ||
| 483 | remove: (sourceId: Source["id"]) => | ||
| 484 | provide(removeSource({ workspaceId, sourceId })), | ||
| 485 | inspection: { | ||
| 486 | get: (sourceId: Source["id"]) => | ||
| 487 | provide(getSourceInspection({ workspaceId, sourceId })), | ||
| 488 | tool: ({ sourceId, toolPath }: { sourceId: Source["id"]; toolPath: string }) => | ||
| 489 | provide( | ||
| 490 | getSourceInspectionToolDetail({ | ||
| 491 | workspaceId, | ||
| 492 | sourceId, | ||
| 493 | toolPath, | ||
| 494 | }), | ||
| 495 | ), | ||
| 496 | discover: ({ | ||
| 497 | sourceId, | ||
| 498 | payload, | ||
| 499 | }: { | ||
| 500 | sourceId: Source["id"]; | ||
| 501 | payload: Parameters<typeof discoverSourceInspectionTools>[0]["payload"]; | ||
| 502 | }) => | ||
| 503 | provide( | ||
| 504 | discoverSourceInspectionTools({ | ||
| 505 | workspaceId, | ||
| 506 | sourceId, | ||
| 507 | payload, | ||
| 508 | }), | ||
| 509 | ), | ||
| 510 | }, | ||
| 511 | oauthClients: { | ||
| 512 | list: (providerKey: string) => | ||
| 513 | provideSourceAuth((service) => | ||
| 514 | service.listWorkspaceOauthClients({ | ||
| 515 | workspaceId, | ||
| 516 | providerKey, | ||
| 517 | }), | ||
| 518 | ), | ||
| 519 | create: (payload: CreateWorkspaceOauthClientPayload) => | ||
| 520 | provideSourceAuth((service) => | ||
| 521 | service.createWorkspaceOauthClient({ | ||
| 522 | workspaceId, | ||
| 523 | providerKey: payload.providerKey, | ||
| 524 | label: payload.label, | ||
| 525 | oauthClient: payload.oauthClient, | ||
| 526 | }), | ||
| 527 | ), | ||
| 528 | remove: (oauthClientId: WorkspaceOauthClient["id"]) => | ||
| 529 | provideSourceAuth((service) => | ||
| 530 | service.removeWorkspaceOauthClient({ | ||
| 531 | workspaceId, | ||
| 532 | oauthClientId, | ||
| 533 | }), | ||
| 534 | ), | ||
| 535 | }, | ||
| 536 | providerGrants: { | ||
| 537 | remove: (grantId: ProviderAuthGrant["id"]) => | ||
| 538 | provideSourceAuth((service) => | ||
| 539 | service.removeProviderAuthGrant({ | ||
| 540 | workspaceId, | ||
| 541 | grantId, | ||
| 542 | }), | ||
| 543 | ), | ||
| 544 | }, | ||
| 545 | }, | ||
| 546 | oauth: { | ||
| 547 | startSourceAuth: (input: ExecutorSourceOAuthInput) => | ||
| 548 | provideSourceAuth((service) => | ||
| 549 | service.startSourceOAuthSession({ | ||
| 550 | ...input, | ||
| 551 | workspaceId, | ||
| 552 | actorAccountId: accountId, | ||
| 553 | }), | ||
| 554 | ), | ||
| 555 | completeSourceAuth: ({ state, code, error, errorDescription }) => | ||
| 556 | provideSourceAuth((service) => | ||
| 557 | service.completeSourceOAuthSession({ | ||
| 558 | state, | ||
| 559 | code, | ||
| 560 | error, | ||
| 561 | errorDescription, | ||
| 562 | }), | ||
| 563 | ), | ||
| 564 | completeProviderCallback: (input) => | ||
| 565 | provideSourceAuth((service) => | ||
| 566 | service.completeProviderOauthCallback({ | ||
| 567 | ...input, | ||
| 568 | workspaceId: input.workspaceId ?? workspaceId, | ||
| 569 | actorAccountId: input.actorAccountId ?? accountId, | ||
| 570 | }), | ||
| 571 | ), | ||
| 572 | }, | ||
| 573 | executions: { | ||
| 574 | create: (payload: CreateExecutionPayload) => | ||
| 575 | provide( | ||
| 576 | createExecution({ | ||
| 577 | workspaceId, | ||
| 578 | payload, | ||
| 579 | createdByAccountId: accountId, | ||
| 580 | }), | ||
| 581 | ), | ||
| 582 | get: (executionId: Execution["id"]) => | ||
| 583 | provide(getExecution({ workspaceId, executionId })), | ||
| 584 | resume: (executionId: Execution["id"], payload: ResumeExecutionPayload) => | ||
| 585 | provide( | ||
| 586 | resumeExecution({ | ||
| 587 | workspaceId, | ||
| 588 | executionId, | ||
| 589 | payload, | ||
| 590 | resumedByAccountId: accountId, | ||
| 591 | }), | ||
| 592 | ), | ||
| 593 | }, | ||
| 594 | } satisfies Executor["effect"]; | ||
| 595 | |||
| 596 | return { | ||
| 597 | runtime, | ||
| 598 | installation, | ||
| 599 | workspaceId, | ||
| 600 | accountId, | ||
| 601 | provide, | ||
| 602 | run, | ||
| 603 | close: () => runtime.close(), | ||
| 604 | effect, | ||
| 605 | local: { | ||
| 606 | installation: () => run(effect.local.installation()), | ||
| 607 | config: () => run(effect.local.config()), | ||
| 608 | credentials: { | ||
| 609 | get: ({ sourceId, interactionId }) => | ||
| 610 | run(effect.local.credentials.get({ sourceId, interactionId })), | ||
| 611 | submit: ({ sourceId, interactionId, action, token }) => | ||
| 612 | run(effect.local.credentials.submit({ sourceId, interactionId, action, token })), | ||
| 613 | complete: ({ sourceId, state, code, error, errorDescription }) => | ||
| 614 | run(effect.local.credentials.complete({ sourceId, state, code, error, errorDescription })), | ||
| 615 | }, | ||
| 616 | }, | ||
| 617 | secrets: { | ||
| 618 | list: () => run(effect.secrets.list()), | ||
| 619 | create: (payload) => run(effect.secrets.create(payload)), | ||
| 620 | update: (input) => run(effect.secrets.update(input)), | ||
| 621 | remove: (secretId) => run(effect.secrets.remove(secretId)), | ||
| 622 | }, | ||
| 623 | policies: { | ||
| 624 | list: () => run(effect.policies.list()), | ||
| 625 | create: (payload) => run(effect.policies.create(payload)), | ||
| 626 | get: (policyId) => run(effect.policies.get(policyId)), | ||
| 627 | update: (policyId, payload) => | ||
| 628 | run(effect.policies.update(policyId, payload)), | ||
| 629 | remove: async (policyId) => | ||
| 630 | (await run(effect.policies.remove(policyId))).removed, | ||
| 631 | }, | ||
| 632 | sources: { | ||
| 633 | add: (input, options) => run(effect.sources.add(input, options)), | ||
| 634 | connect: (payload) => run(effect.sources.connect(payload)), | ||
| 635 | connectBatch: (payload) => run(effect.sources.connectBatch(payload)), | ||
| 636 | discover: (input) => run(effect.sources.discover(input)), | ||
| 637 | list: () => run(effect.sources.list()), | ||
| 638 | create: (payload) => run(effect.sources.create(payload)), | ||
| 639 | get: (sourceId) => run(effect.sources.get(sourceId)), | ||
| 640 | update: (sourceId, payload) => | ||
| 641 | run(effect.sources.update(sourceId, payload)), | ||
| 642 | remove: async (sourceId) => | ||
| 643 | (await run(effect.sources.remove(sourceId))).removed, | ||
| 644 | inspection: { | ||
| 645 | get: (sourceId) => run(effect.sources.inspection.get(sourceId)), | ||
| 646 | tool: ({ sourceId, toolPath }) => | ||
| 647 | run(effect.sources.inspection.tool({ sourceId, toolPath })), | ||
| 648 | discover: ({ sourceId, payload }) => | ||
| 649 | run(effect.sources.inspection.discover({ sourceId, payload })), | ||
| 650 | }, | ||
| 651 | oauthClients: { | ||
| 652 | list: (providerKey) => | ||
| 653 | run(effect.sources.oauthClients.list(providerKey)), | ||
| 654 | create: (payload) => run(effect.sources.oauthClients.create(payload)), | ||
| 655 | remove: (oauthClientId) => | ||
| 656 | run(effect.sources.oauthClients.remove(oauthClientId)), | ||
| 657 | }, | ||
| 658 | providerGrants: { | ||
| 659 | remove: (grantId) => | ||
| 660 | run(effect.sources.providerGrants.remove(grantId)), | ||
| 661 | }, | ||
| 662 | }, | ||
| 663 | oauth: { | ||
| 664 | startSourceAuth: (input) => run(effect.oauth.startSourceAuth(input)), | ||
| 665 | completeSourceAuth: ({ state, code, error, errorDescription }) => | ||
| 666 | run(effect.oauth.completeSourceAuth({ state, code, error, errorDescription })), | ||
| 667 | completeProviderCallback: (input) => | ||
| 668 | run(effect.oauth.completeProviderCallback(input)), | ||
| 669 | }, | ||
| 670 | executions: { | ||
| 671 | create: (payload) => run(effect.executions.create(payload)), | ||
| 672 | get: (executionId) => run(effect.executions.get(executionId)), | ||
| 673 | resume: (executionId, payload) => | ||
| 674 | run(effect.executions.resume(executionId, payload)), | ||
| 675 | }, | ||
| 676 | }; | ||
| 677 | }; | ||
| 678 | |||
| 679 | export const createExecutorEffect = ( | ||
| 680 | options: CreateExecutorOptions, | ||
| 681 | ): Effect.Effect<Executor, Error> => | ||
| 682 | Effect.map( | ||
| 683 | options.backend.createRuntime({ | ||
| 684 | executionResolver: options.executionResolver, | ||
| 685 | createInternalToolMap: options.createInternalToolMap, | ||
| 686 | resolveSecretMaterial: options.resolveSecretMaterial, | ||
| 687 | getLocalServerBaseUrl: options.getLocalServerBaseUrl, | ||
| 688 | }), | ||
| 689 | fromRuntime, | ||
| 690 | ); | ||
| 691 | |||
| 692 | export const createExecutor = async ( | ||
| 693 | options: CreateExecutorOptions, | ||
| 694 | ): Promise<Executor> => Effect.runPromise(createExecutorEffect(options)); | ||
| @@ -1,12 +1,2 @@ | |||
| 1 | export * from "./errors"; | 1 | export * from "./backend"; |
| 2 | export * from "./string-schemas"; | 2 | export * from "./executor"; |
| 3 | export * from "./executions/contracts"; | ||
| 4 | export * from "./local/contracts"; | ||
| 5 | export * from "./local/operations"; | ||
| 6 | export * from "./local/secrets"; | ||
| 7 | export * from "./policies/contracts"; | ||
| 8 | export * from "./policies/operations"; | ||
| 9 | export * from "./sources/contracts"; | ||
| 10 | export * from "./sources/discovery"; | ||
| 11 | export * from "./sources/inspection"; | ||
| 12 | export * from "./sources/operations"; | ||
| @@ -0,0 +1,6 @@ | |||
| 1 | export * from "./local/operations"; | ||
| 2 | export * from "./local/secrets"; | ||
| 3 | export * from "./policies/operations"; | ||
| 4 | export * from "./sources/discovery"; | ||
| 5 | export * from "./sources/inspection"; | ||
| 6 | export * from "./sources/operations"; | ||
| @@ -23,15 +23,15 @@ import { · 22 unmodified lines | |||
| 23 | import type { ToolPath } from "@executor/codemode-core"; | 23 | import type { ToolPath } from "@executor/codemode-core"; |
| 24 | import { createCatalogImportMetadata } from "@executor/source-core"; | 24 | import { createCatalogImportMetadata } from "@executor/source-core"; |
| 25 | import { createGraphqlCatalogFragment } from "@executor/source-graphql"; | 25 | import { createGraphqlCatalogFragment } from "@executor/source-graphql"; |
| 26 | import { createExecutorAdminToolMap } from "../../../internal/src/index"; | 26 | import { createWorkspaceExecutorAdminToolMap } from "../../../internal/src/index"; |
| 27 | 27 | ||
| 28 | import { | 28 | import { |
| 29 | type ControlPlaneRuntime, | 29 | type ControlPlaneRuntime, |
| 30 | createControlPlaneRuntime, | ||
| 31 | LiveExecutionManagerService, | 30 | LiveExecutionManagerService, |
| 32 | provideControlPlaneRuntime, | 31 | provideControlPlaneRuntime, |
| 33 | RuntimeExecutionResolverService, | 32 | RuntimeExecutionResolverService, |
| 34 | } from "./index"; | 33 | } from "./index"; |
| 34 | import { createLocalControlPlaneRuntime as createControlPlaneRuntime } from "../../../sdk-file/src/index"; | ||
| 35 | import { createSourceFromPayload } from "./sources/source-definitions"; | 35 | import { createSourceFromPayload } from "./sources/source-definitions"; |
| 36 | import { decodeSourceCredentialSelectionContent } from "./sources/source-credential-interactions"; | 36 | import { decodeSourceCredentialSelectionContent } from "./sources/source-credential-interactions"; |
| 37 | import { persistSource } from "./sources/source-store"; | 37 | import { persistSource } from "./sources/source-store"; |
| @@ -67,7 +67,7 @@ const makeRuntime = Effect.gen(function* () { · 29 unmodified lines | |||
| 67 | workspaceRoot, | 67 | workspaceRoot, |
| 68 | homeConfigPath, | 68 | homeConfigPath, |
| 69 | homeStateDirectory, | 69 | homeStateDirectory, |
| 70 | createInternalToolMap: createExecutorAdminToolMap, | 70 | createInternalToolMap: createWorkspaceExecutorAdminToolMap, |
| 71 | }), | 71 | }), |
| 72 | (runtime) => Effect.promise(() => runtime.close()).pipe(Effect.orDie), | 72 | (runtime) => Effect.promise(() => runtime.close()).pipe(Effect.orDie), |
| 73 | ); | 73 | ); |
| @@ -9,9 +9,7 @@ import * as Schema from "effect/Schema"; · 8 unmodified lines | |||
| 9 | import { makeToolInvokerFromTools } from "@executor/codemode-core"; | 9 | import { makeToolInvokerFromTools } from "@executor/codemode-core"; |
| 10 | import { makeDenoSubprocessExecutor } from "@executor/runtime-deno-subprocess"; | 10 | import { makeDenoSubprocessExecutor } from "@executor/runtime-deno-subprocess"; |
| 11 | 11 | ||
| 12 | import { | 12 | import { createLocalControlPlaneRuntime as createControlPlaneRuntime } from "../../../../sdk-file/src/index"; |
| 13 | createControlPlaneRuntime, | ||
| 14 | } from "../index"; | ||
| 15 | import { withControlPlaneClient } from "./test-http-client"; | 13 | import { withControlPlaneClient } from "./test-http-client"; |
| 16 | 14 | ||
| 17 | const makeExecutionResolver = () => { | 15 | const makeExecutionResolver = () => { |
| @@ -20,9 +20,9 @@ import { discoverMcpToolsFromConnector } from "@executor/source-mcp"; · 19 unmodified lines | |||
| 20 | import { makeDenoSubprocessExecutor } from "@executor/runtime-deno-subprocess"; | 20 | import { makeDenoSubprocessExecutor } from "@executor/runtime-deno-subprocess"; |
| 21 | 21 | ||
| 22 | import { | 22 | import { |
| 23 | createControlPlaneRuntime, | ||
| 24 | type ResolveExecutionEnvironment, | 23 | type ResolveExecutionEnvironment, |
| 25 | } from "../index"; | 24 | } from "../index"; |
| 25 | import { createLocalControlPlaneRuntime as createControlPlaneRuntime } from "../../../../sdk-file/src/index"; | ||
| 26 | import { withControlPlaneClient } from "./test-http-client"; | 26 | import { withControlPlaneClient } from "./test-http-client"; |
| 27 | 27 | ||
| 28 | type McpFormServer = { | 28 | type McpFormServer = { |
| @@ -5,9 +5,7 @@ import { NodeFileSystem } from "@effect/platform-node"; · 4 unmodified lines | |||
| 5 | import { describe, expect, it } from "@effect/vitest"; | 5 | import { describe, expect, it } from "@effect/vitest"; |
| 6 | import * as Effect from "effect/Effect"; | 6 | import * as Effect from "effect/Effect"; |
| 7 | 7 | ||
| 8 | import { | 8 | import { createLocalControlPlaneRuntime as createControlPlaneRuntime } from "../../../../sdk-file/src/index"; |
| 9 | createControlPlaneRuntime, | ||
| 10 | } from "../index"; | ||
| 11 | import { withControlPlaneClient } from "./test-http-client"; | 9 | import { withControlPlaneClient } from "./test-http-client"; |
| 12 | 10 | ||
| 13 | const writeProjectConfig = ( | 11 | const writeProjectConfig = ( |
| @@ -11,11 +11,21 @@ import * as Effect from "effect/Effect"; · 10 unmodified lines | |||
| 11 | import * as Layer from "effect/Layer"; | 11 | import * as Layer from "effect/Layer"; |
| 12 | 12 | ||
| 13 | import { | 13 | import { |
| 14 | createExecutorEffect, | ||
| 14 | type ControlPlaneRuntime, | 15 | type ControlPlaneRuntime, |
| 15 | } from "../index"; | 16 | } from "../../index"; |
| 16 | 17 | ||
| 17 | const createClientLayer = (runtime: ControlPlaneRuntime) => { | 18 | const createClientLayer = (runtime: ControlPlaneRuntime) => { |
| 18 | const apiLayer = createControlPlaneApiLayer(runtime.runtimeLayer); | 19 | const apiLayer = Layer.unwrapEffect( |
| 20 | Effect.map( | ||
| 21 | createExecutorEffect({ | ||
| 22 | backend: { | ||
| 23 | createRuntime: () => Effect.succeed(runtime), | ||
| 24 | }, | ||
| 25 | }), | ||
| 26 | createControlPlaneApiLayer, | ||
| 27 | ), | ||
| 28 | ); | ||
| 19 | 29 | ||
| 20 | return HttpApiBuilder.serve().pipe( | 30 | return HttpApiBuilder.serve().pipe( |
| 21 | Layer.provide(apiLayer), | 31 | Layer.provide(apiLayer), |
| @@ -26,6 +26,8 @@ import { · 25 unmodified lines | |||
| 26 | type LocalToolRuntime, | 26 | type LocalToolRuntime, |
| 27 | } from "../../local/tools"; | 27 | } from "../../local/tools"; |
| 28 | import { | 28 | import { |
| 29 | InstallationStore, | ||
| 30 | type InstallationStoreShape, | ||
| 29 | SourceArtifactStore, | 31 | SourceArtifactStore, |
| 30 | type SourceArtifactStoreShape, | 32 | type SourceArtifactStoreShape, |
| 31 | WorkspaceConfigStore, | 33 | WorkspaceConfigStore, |
| @@ -65,6 +67,7 @@ export const createWorkspaceExecutionEnvironmentResolver = · 33 unmodified lines | |||
| 65 | typeof RuntimeSourceCatalogStoreService | 67 | typeof RuntimeSourceCatalogStoreService |
| 66 | >; | 68 | >; |
| 67 | localToolRuntimeLoader: LocalToolRuntimeLoaderShape; | 69 | localToolRuntimeLoader: LocalToolRuntimeLoaderShape; |
| 70 | installationStore: InstallationStoreShape; | ||
| 68 | workspaceConfigStore: WorkspaceConfigStoreShape; | 71 | workspaceConfigStore: WorkspaceConfigStoreShape; |
| 69 | workspaceStateStore: WorkspaceStateStoreShape; | 72 | workspaceStateStore: WorkspaceStateStoreShape; |
| 70 | sourceArtifactStore: SourceArtifactStoreShape; | 73 | sourceArtifactStore: SourceArtifactStoreShape; |
| @@ -92,6 +95,7 @@ export const createWorkspaceExecutionEnvironmentResolver = · 21 unmodified lines | |||
| 92 | sourceStore: input.sourceStore, | 95 | sourceStore: input.sourceStore, |
| 93 | sourceCatalogSyncService: input.sourceCatalogSyncService, | 96 | sourceCatalogSyncService: input.sourceCatalogSyncService, |
| 94 | sourceCatalogStore: input.sourceCatalogStore, | 97 | sourceCatalogStore: input.sourceCatalogStore, |
| 98 | installationStore: input.installationStore, | ||
| 95 | workspaceConfigStore: input.workspaceConfigStore, | 99 | workspaceConfigStore: input.workspaceConfigStore, |
| 96 | workspaceStateStore: input.workspaceStateStore, | 100 | workspaceStateStore: input.workspaceStateStore, |
| 97 | sourceArtifactStore: input.sourceArtifactStore, | 101 | sourceArtifactStore: input.sourceArtifactStore, |
| @@ -141,6 +145,7 @@ export const RuntimeExecutionResolverLive = ( · 43 unmodified lines | |||
| 141 | const sourceAuthService = yield* RuntimeSourceAuthServiceTag; | 145 | const sourceAuthService = yield* RuntimeSourceAuthServiceTag; |
| 142 | const sourceCatalogStore = yield* RuntimeSourceCatalogStoreService; | 146 | const sourceCatalogStore = yield* RuntimeSourceCatalogStoreService; |
| 143 | const localToolRuntimeLoader = yield* LocalToolRuntimeLoaderService; | 147 | const localToolRuntimeLoader = yield* LocalToolRuntimeLoaderService; |
| 148 | const installationStore = yield* InstallationStore; | ||
| 144 | const workspaceConfigStore = yield* WorkspaceConfigStore; | 149 | const workspaceConfigStore = yield* WorkspaceConfigStore; |
| 145 | const workspaceStateStore = yield* WorkspaceStateStore; | 150 | const workspaceStateStore = yield* WorkspaceStateStore; |
| 146 | const sourceArtifactStore = yield* SourceArtifactStore; | 151 | const sourceArtifactStore = yield* SourceArtifactStore; |
| @@ -153,6 +158,7 @@ export const RuntimeExecutionResolverLive = ( · 6 unmodified lines | |||
| 153 | sourceAuthMaterialService, | 158 | sourceAuthMaterialService, |
| 154 | sourceCatalogStore, | 159 | sourceCatalogStore, |
| 155 | localToolRuntimeLoader, | 160 | localToolRuntimeLoader, |
| 161 | installationStore, | ||
| 156 | workspaceConfigStore, | 162 | workspaceConfigStore, |
| 157 | workspaceStateStore, | 163 | workspaceStateStore, |
| 158 | sourceArtifactStore, | 164 | sourceArtifactStore, |
| @@ -16,6 +16,7 @@ import { RuntimeSourceCatalogStoreService } from "../../catalog/source/runtime"; · 15 unmodified lines | |||
| 16 | import type { RuntimeLocalWorkspaceState } from "../../local/runtime-context"; | 16 | import type { RuntimeLocalWorkspaceState } from "../../local/runtime-context"; |
| 17 | import { type LocalToolRuntime } from "../../local/tools"; | 17 | import { type LocalToolRuntime } from "../../local/tools"; |
| 18 | import { | 18 | import { |
| 19 | type InstallationStoreShape, | ||
| 19 | makeWorkspaceStorageLayer, | 20 | makeWorkspaceStorageLayer, |
| 20 | type SourceArtifactStoreShape, | 21 | type SourceArtifactStoreShape, |
| 21 | type WorkspaceConfigStoreShape, | 22 | type WorkspaceConfigStoreShape, |
| @@ -47,6 +48,7 @@ export type WorkspaceInternalToolContext = { · 25 unmodified lines | |||
| 47 | typeof RuntimeSourceCatalogSyncService | 48 | typeof RuntimeSourceCatalogSyncService |
| 48 | >; | 49 | >; |
| 49 | sourceAuthService: RuntimeSourceAuthService; | 50 | sourceAuthService: RuntimeSourceAuthService; |
| 51 | installationStore: InstallationStoreShape; | ||
| 50 | workspaceConfigStore: WorkspaceConfigStoreShape; | 52 | workspaceConfigStore: WorkspaceConfigStoreShape; |
| 51 | workspaceStateStore: WorkspaceStateStoreShape; | 53 | workspaceStateStore: WorkspaceStateStoreShape; |
| 52 | sourceArtifactStore: SourceArtifactStoreShape; | 54 | sourceArtifactStore: SourceArtifactStoreShape; |
| @@ -68,6 +70,7 @@ export const createWorkspaceToolInvoker = (input: { · 15 unmodified lines | |||
| 68 | sourceCatalogStore: Effect.Effect.Success< | 70 | sourceCatalogStore: Effect.Effect.Success< |
| 69 | typeof RuntimeSourceCatalogStoreService | 71 | typeof RuntimeSourceCatalogStoreService |
| 70 | >; | 72 | >; |
| 73 | installationStore: InstallationStoreShape; | ||
| 71 | workspaceConfigStore: WorkspaceConfigStoreShape; | 74 | workspaceConfigStore: WorkspaceConfigStoreShape; |
| 72 | workspaceStateStore: WorkspaceStateStoreShape; | 75 | workspaceStateStore: WorkspaceStateStoreShape; |
| 73 | sourceArtifactStore: SourceArtifactStoreShape; | 76 | sourceArtifactStore: SourceArtifactStoreShape; |
| @@ -97,6 +100,10 @@ export const createWorkspaceToolInvoker = (input: { · 23 unmodified lines | |||
| 97 | workspaceId: input.workspaceId, | 100 | workspaceId: input.workspaceId, |
| 98 | accountId: input.accountId, | 101 | accountId: input.accountId, |
| 99 | sourceAuthService: input.sourceAuthService, | 102 | sourceAuthService: input.sourceAuthService, |
| 103 | installationStore: input.installationStore, | ||
| 104 | workspaceConfigStore: input.workspaceConfigStore, | ||
| 105 | workspaceStateStore: input.workspaceStateStore, | ||
| 106 | sourceArtifactStore: input.sourceArtifactStore, | ||
| 100 | runtimeLocalWorkspace: input.runtimeLocalWorkspace, | 107 | runtimeLocalWorkspace: input.runtimeLocalWorkspace, |
| 101 | }); | 108 | }); |
| 102 | const internalTools = | 109 | const internalTools = |
| @@ -107,6 +114,7 @@ export const createWorkspaceToolInvoker = (input: { · 4 unmodified lines | |||
| 107 | sourceStore: input.sourceStore, | 114 | sourceStore: input.sourceStore, |
| 108 | sourceCatalogSyncService: input.sourceCatalogSyncService, | 115 | sourceCatalogSyncService: input.sourceCatalogSyncService, |
| 109 | sourceAuthService: input.sourceAuthService, | 116 | sourceAuthService: input.sourceAuthService, |
| 117 | installationStore: input.installationStore, | ||
| 110 | workspaceConfigStore: input.workspaceConfigStore, | 118 | workspaceConfigStore: input.workspaceConfigStore, |
| 111 | workspaceStateStore: input.workspaceStateStore, | 119 | workspaceStateStore: input.workspaceStateStore, |
| 112 | sourceArtifactStore: input.sourceArtifactStore, | 120 | sourceArtifactStore: input.sourceArtifactStore, |
| @@ -1,51 +1,66 @@ | |||
| 1 | import { FileSystem } from "@effect/platform"; | 1 | import { |
| 2 | createToolCatalogFromTools, | ||
| 3 | makeToolInvokerFromTools, | ||
| 4 | type ToolMap, | ||
| 5 | } from "@executor/codemode-core"; | ||
| 6 | import { clearAllMcpConnectionPools } from "@executor/source-mcp"; | ||
| 7 | import type { LocalInstallation } from "#schema"; | ||
| 2 | import * as Effect from "effect/Effect"; | 8 | import * as Effect from "effect/Effect"; |
| 3 | import * as Exit from "effect/Exit"; | ||
| 4 | import * as Layer from "effect/Layer"; | 9 | import * as Layer from "effect/Layer"; |
| 5 | import * as ManagedRuntime from "effect/ManagedRuntime"; | 10 | import * as ManagedRuntime from "effect/ManagedRuntime"; |
| 6 | import * as Scope from "effect/Scope"; | ||
| 7 | import { NodeFileSystem } from "@effect/platform-node"; | ||
| 8 | import { clearAllMcpConnectionPools } from "@executor/source-mcp"; | ||
| 9 | import type { LocalInstallation } from "#schema"; | ||
| 10 | 11 | ||
| 11 | import { type ResolveExecutionEnvironment } from "./execution/state"; | 12 | import { RuntimeSourceAuthMaterialLive } from "./auth/source-auth-material"; |
| 12 | import { | 13 | import { RuntimeSourceCatalogStoreLive } from "./catalog/source/runtime"; |
| 13 | createLiveExecutionManager, | 14 | import { reconcileMissingSourceCatalogArtifacts } from "./catalog/source/reconcile"; |
| 14 | LiveExecutionManagerService, | 15 | import { RuntimeSourceCatalogSyncLive } from "./catalog/source/sync"; |
| 15 | } from "./execution/live"; | 16 | import { createLiveExecutionManager, LiveExecutionManagerService } from "./execution/live"; |
| 16 | import { | 17 | import { RuntimeExecutionResolverLive } from "./execution/workspace/environment"; |
| 17 | createLocalControlPlanePersistence, | 18 | import type { CreateWorkspaceInternalToolMap, WorkspaceInternalToolContext } from "./execution/workspace/tool-invoker"; |
| 18 | type LocalControlPlanePersistence, | 19 | import type { |
| 19 | } from "./local/control-plane-store"; | 20 | LoadedLocalExecutorConfig, |
| 20 | 21 | ResolvedLocalWorkspaceContext, | |
| 21 | import { resolveLocalWorkspaceContext } from "./local/config"; | 22 | } from "./local/config"; |
| 23 | import type { LocalExecutorConfig } from "#schema"; | ||
| 24 | import type { LocalControlPlanePersistence } from "./local/control-plane-store"; | ||
| 22 | import { | 25 | import { |
| 23 | LocalStorageLive, | 26 | type DeleteSecretMaterial, |
| 24 | LocalInstallationStore, | 27 | type ResolveSecretMaterial, |
| 25 | LocalWorkspaceConfigStore, | 28 | SecretMaterialDeleterService, |
| 26 | } from "./local/storage"; | 29 | SecretMaterialResolverService, |
| 30 | SecretMaterialStorerService, | ||
| 31 | SecretMaterialUpdaterService, | ||
| 32 | type StoreSecretMaterial, | ||
| 33 | type UpdateSecretMaterial, | ||
| 34 | } from "./local/secret-material-providers"; | ||
| 35 | import type { LocalSourceArtifact } from "./local/source-artifacts"; | ||
| 27 | import { | 36 | import { |
| 28 | type RuntimeLocalWorkspaceState, | 37 | type RuntimeLocalWorkspaceState, |
| 29 | RuntimeLocalWorkspaceLive, | 38 | RuntimeLocalWorkspaceLive, |
| 30 | } from "./local/runtime-context"; | 39 | } from "./local/runtime-context"; |
| 31 | import { LocalToolRuntimeLoaderLive } from "./local/tools"; | 40 | import { |
| 41 | type LocalToolRuntime, | ||
| 42 | type LocalToolRuntimeLoaderShape, | ||
| 43 | LocalToolRuntimeLoaderService, | ||
| 44 | } from "./local/tools"; | ||
| 45 | import { | ||
| 46 | InstallationStore, | ||
| 47 | makeLocalStorageLayer, | ||
| 48 | type InstallationStoreShape, | ||
| 49 | type SourceArtifactStoreShape, | ||
| 50 | type WorkspaceConfigStoreShape, | ||
| 51 | type WorkspaceStateStoreShape, | ||
| 52 | } from "./local/storage"; | ||
| 53 | import type { LocalWorkspaceState } from "./local/workspace-state"; | ||
| 32 | import { synchronizeLocalWorkspaceState } from "./local/workspace-sync"; | 54 | import { synchronizeLocalWorkspaceState } from "./local/workspace-sync"; |
| 33 | import { ControlPlaneStore, type ControlPlaneStoreShape } from "./store"; | 55 | import { ControlPlaneStore, type ControlPlaneStoreShape } from "./store"; |
| 34 | import { RuntimeSourceStoreLive } from "./sources/source-store"; | ||
| 35 | import { RuntimeSourceCatalogStoreLive } from "./catalog/source/runtime"; | ||
| 36 | import { reconcileMissingSourceCatalogArtifacts } from "./catalog/source/reconcile"; | ||
| 37 | import { RuntimeSourceAuthMaterialLive } from "./auth/source-auth-material"; | ||
| 38 | import { RuntimeSourceCatalogSyncLive } from "./catalog/source/sync"; | ||
| 39 | import { RuntimeSourceAuthServiceLive } from "./sources/source-auth-service"; | 56 | import { RuntimeSourceAuthServiceLive } from "./sources/source-auth-service"; |
| 40 | import type { ResolveSecretMaterial } from "./local/secret-material-providers"; | 57 | import { RuntimeSourceStoreLive } from "./sources/source-store"; |
| 41 | import { SecretMaterialLive } from "./local/secret-material-providers"; | ||
| 42 | import { RuntimeExecutionResolverLive } from "./execution/workspace/environment"; | ||
| 43 | import type { CreateWorkspaceInternalToolMap } from "./execution/workspace/tool-invoker"; | ||
| 44 | 58 | ||
| 45 | export * from "./execution/state"; | 59 | export * from "./execution/state"; |
| 46 | export * from "./sources/executor-tools"; | 60 | export * from "./sources/executor-tools"; |
| 47 | export * from "./execution/live"; | 61 | export * from "./execution/live"; |
| 48 | export * from "./local/config"; | 62 | export * from "./local/config"; |
| 63 | export * from "./local/control-plane-store"; | ||
| 49 | export * from "./local/errors"; | 64 | export * from "./local/errors"; |
| 50 | export * from "./local/installation"; | 65 | export * from "./local/installation"; |
| 51 | export * from "./local/runtime-context"; | 66 | export * from "./local/runtime-context"; |
| @@ -89,54 +104,157 @@ export type RuntimeControlPlaneOptions = { · 37 unmodified lines | |||
| 89 | createInternalToolMap?: CreateWorkspaceInternalToolMap; | 104 | createInternalToolMap?: CreateWorkspaceInternalToolMap; |
| 90 | resolveSecretMaterial?: ResolveSecretMaterial; | 105 | resolveSecretMaterial?: ResolveSecretMaterial; |
| 91 | getLocalServerBaseUrl?: () => string | undefined; | 106 | getLocalServerBaseUrl?: () => string | undefined; |
| 92 | localDataDir?: string; | ||
| 93 | workspaceRoot?: string; | ||
| 94 | homeConfigPath?: string; | ||
| 95 | homeStateDirectory?: string; | ||
| 96 | }; | 107 | }; |
| 97 | 108 | ||
| 109 | type ResolveExecutionEnvironment = import("./execution/state").ResolveExecutionEnvironment; | ||
| 110 | |||
| 98 | const detailsFromCause = (cause: unknown): string => | 111 | const detailsFromCause = (cause: unknown): string => |
| 99 | cause instanceof Error ? cause.message : String(cause); | 112 | cause instanceof Error ? cause.message : String(cause); |
| 100 | 113 | ||
| 101 | const toLocalRuntimeBootstrapError = (cause: unknown): Error => { | 114 | const toRuntimeBootstrapError = (cause: unknown): Error => { |
| 102 | const details = detailsFromCause(cause); | 115 | const details = detailsFromCause(cause); |
| 103 | return new Error(`Failed initializing local runtime: ${details}`); | 116 | return new Error(`Failed initializing runtime: ${details}`); |
| 104 | }; | 117 | }; |
| 105 | 118 | ||
| 106 | const closeScope = (scope: Scope.CloseableScope) => | ||
| 107 | Scope.close(scope, Exit.void).pipe(Effect.orDie); | ||
| 108 | |||
| 109 | export type RuntimeControlPlaneLayer = Layer.Layer<any, never, never>; | 119 | export type RuntimeControlPlaneLayer = Layer.Layer<any, never, never>; |
| 110 | 120 | ||
| 121 | export type BoundInstallationStore = { | ||
| 122 | load: () => Effect.Effect<LocalInstallation, Error, never>; | ||
| 123 | getOrProvision: () => Effect.Effect<LocalInstallation, Error, never>; | ||
| 124 | }; | ||
| 125 | |||
| 126 | export type BoundWorkspaceConfigStore = { | ||
| 127 | load: () => Effect.Effect<LoadedLocalExecutorConfig, Error, never>; | ||
| 128 | writeProject: ( | ||
| 129 | config: LocalExecutorConfig, | ||
| 130 | ) => Effect.Effect<void, Error, never>; | ||
| 131 | resolveRelativePath: WorkspaceConfigStoreShape["resolveRelativePath"]; | ||
| 132 | }; | ||
| 133 | |||
| 134 | export type BoundWorkspaceStateStore = { | ||
| 135 | load: () => Effect.Effect<LocalWorkspaceState, Error, never>; | ||
| 136 | write: ( | ||
| 137 | state: LocalWorkspaceState, | ||
| 138 | ) => Effect.Effect<void, Error, never>; | ||
| 139 | }; | ||
| 140 | |||
| 141 | export type BoundSourceArtifactStore = { | ||
| 142 | build: SourceArtifactStoreShape["build"]; | ||
| 143 | read: ( | ||
| 144 | sourceId: string, | ||
| 145 | ) => Effect.Effect<LocalSourceArtifact | null, Error, never>; | ||
| 146 | write: (input: { | ||
| 147 | sourceId: string; | ||
| 148 | artifact: LocalSourceArtifact; | ||
| 149 | }) => Effect.Effect<void, Error, never>; | ||
| 150 | remove: (sourceId: string) => Effect.Effect<void, Error, never>; | ||
| 151 | }; | ||
| 152 | |||
| 153 | export type BoundLocalToolRuntimeLoader = { | ||
| 154 | load: () => ReturnType<LocalToolRuntimeLoaderShape["load"]>; | ||
| 155 | }; | ||
| 156 | |||
| 157 | export type RuntimeSecretMaterialServices = { | ||
| 158 | resolve: ResolveSecretMaterial; | ||
| 159 | store: StoreSecretMaterial; | ||
| 160 | delete: DeleteSecretMaterial; | ||
| 161 | update: UpdateSecretMaterial; | ||
| 162 | }; | ||
| 163 | |||
| 164 | export type RuntimeControlPlaneServices = { | ||
| 165 | workspaceContext: ResolvedLocalWorkspaceContext; | ||
| 166 | installationStore: BoundInstallationStore; | ||
| 167 | workspaceConfigStore: BoundWorkspaceConfigStore; | ||
| 168 | workspaceStateStore: BoundWorkspaceStateStore; | ||
| 169 | sourceArtifactStore: BoundSourceArtifactStore; | ||
| 170 | localToolRuntimeLoader?: BoundLocalToolRuntimeLoader; | ||
| 171 | secretMaterial: RuntimeSecretMaterialServices; | ||
| 172 | persistence: LocalControlPlanePersistence; | ||
| 173 | }; | ||
| 174 | |||
| 175 | const emptyToolRuntime = (): LocalToolRuntime => { | ||
| 176 | const tools: ToolMap = {}; | ||
| 177 | return { | ||
| 178 | tools, | ||
| 179 | catalog: createToolCatalogFromTools({ tools }), | ||
| 180 | toolInvoker: makeToolInvokerFromTools({ tools }), | ||
| 181 | toolPaths: new Set(), | ||
| 182 | }; | ||
| 183 | }; | ||
| 184 | |||
| 185 | const toInstallationStoreShape = ( | ||
| 186 | input: BoundInstallationStore, | ||
| 187 | ): InstallationStoreShape => ({ | ||
| 188 | load: () => input.load(), | ||
| 189 | getOrProvision: () => input.getOrProvision(), | ||
| 190 | }); | ||
| 191 | |||
| 192 | const toWorkspaceConfigStoreShape = ( | ||
| 193 | input: BoundWorkspaceConfigStore, | ||
| 194 | ): WorkspaceConfigStoreShape => ({ | ||
| 195 | load: () => input.load(), | ||
| 196 | writeProject: ({ config }) => input.writeProject(config), | ||
| 197 | resolveRelativePath: input.resolveRelativePath, | ||
| 198 | }); | ||
| 199 | |||
| 200 | const toWorkspaceStateStoreShape = ( | ||
| 201 | input: BoundWorkspaceStateStore, | ||
| 202 | ): WorkspaceStateStoreShape => ({ | ||
| 203 | load: () => input.load(), | ||
| 204 | write: ({ state }) => input.write(state), | ||
| 205 | }); | ||
| 206 | |||
| 207 | const toSourceArtifactStoreShape = ( | ||
| 208 | input: BoundSourceArtifactStore, | ||
| 209 | ): SourceArtifactStoreShape => ({ | ||
| 210 | build: input.build, | ||
| 211 | read: ({ sourceId }) => input.read(sourceId), | ||
| 212 | write: ({ sourceId, artifact }) => input.write({ sourceId, artifact }), | ||
| 213 | remove: ({ sourceId }) => input.remove(sourceId), | ||
| 214 | }); | ||
| 215 | |||
| 216 | const makeSecretMaterialLayer = (input: RuntimeSecretMaterialServices) => | ||
| 217 | Layer.mergeAll( | ||
| 218 | Layer.succeed(SecretMaterialResolverService, input.resolve), | ||
| 219 | Layer.succeed(SecretMaterialStorerService, input.store), | ||
| 220 | Layer.succeed(SecretMaterialDeleterService, input.delete), | ||
| 221 | Layer.succeed(SecretMaterialUpdaterService, input.update), | ||
| 222 | ); | ||
| 223 | |||
| 111 | export const createRuntimeControlPlaneLayer = ( | 224 | export const createRuntimeControlPlaneLayer = ( |
| 112 | input: RuntimeControlPlaneOptions & { | 225 | input: RuntimeControlPlaneOptions & RuntimeControlPlaneServices & { |
| 113 | store: ControlPlaneStoreShape; | 226 | store: ControlPlaneStoreShape; |
| 114 | localWorkspaceState: RuntimeLocalWorkspaceState; | 227 | localWorkspaceState: RuntimeLocalWorkspaceState; |
| 115 | liveExecutionManager: ReturnType<typeof createLiveExecutionManager>; | 228 | liveExecutionManager: ReturnType<typeof createLiveExecutionManager>; |
| 116 | }, | 229 | }, |
| 117 | ) => { | 230 | ) => { |
| 118 | const platformLayer = NodeFileSystem.layer; | 231 | const storageLayer = makeLocalStorageLayer({ |
| 119 | const storageLayer = LocalStorageLive.pipe(Layer.provide(platformLayer)); | 232 | installationStore: toInstallationStoreShape(input.installationStore), |
| 120 | const localToolRuntimeLayer = LocalToolRuntimeLoaderLive.pipe( | 233 | workspaceConfigStore: toWorkspaceConfigStoreShape(input.workspaceConfigStore), |
| 121 | Layer.provide(platformLayer), | 234 | workspaceStateStore: toWorkspaceStateStoreShape(input.workspaceStateStore), |
| 235 | sourceArtifactStore: toSourceArtifactStoreShape(input.sourceArtifactStore), | ||
| 236 | }); | ||
| 237 | const localToolRuntimeLayer = Layer.succeed( | ||
| 238 | LocalToolRuntimeLoaderService, | ||
| 239 | LocalToolRuntimeLoaderService.of({ | ||
| 240 | load: () => | ||
| 241 | input.localToolRuntimeLoader?.load() ?? Effect.succeed(emptyToolRuntime()), | ||
| 242 | }), | ||
| 122 | ); | 243 | ); |
| 123 | 244 | ||
| 124 | const baseLayer = Layer.mergeAll( | 245 | const baseLayer = Layer.mergeAll( |
| 125 | platformLayer, | ||
| 126 | Layer.succeed(ControlPlaneStore, input.store), | 246 | Layer.succeed(ControlPlaneStore, input.store), |
| 127 | RuntimeLocalWorkspaceLive(input.localWorkspaceState), | 247 | RuntimeLocalWorkspaceLive(input.localWorkspaceState), |
| 128 | storageLayer, | 248 | storageLayer, |
| 129 | Layer.succeed(LiveExecutionManagerService, input.liveExecutionManager), | 249 | Layer.succeed(LiveExecutionManagerService, input.liveExecutionManager), |
| 130 | ); | 250 | ); |
| 131 | 251 | ||
| 132 | const secretMaterialLayer = SecretMaterialLive({ | 252 | const secretMaterialLayer = makeSecretMaterialLayer(input.secretMaterial).pipe( |
| 133 | resolveSecretMaterial: input.resolveSecretMaterial, | ||
| 134 | }).pipe(Layer.provide(baseLayer)); | ||
| 135 | |||
| 136 | const sourceStoreLayer = RuntimeSourceStoreLive.pipe( | ||
| 137 | Layer.provide(baseLayer), | 253 | Layer.provide(baseLayer), |
| 138 | ); | 254 | ); |
| 139 | 255 | ||
| 256 | const sourceStoreLayer = RuntimeSourceStoreLive.pipe(Layer.provide(baseLayer)); | ||
| 257 | |||
| 140 | const sourceCatalogStoreLayer = RuntimeSourceCatalogStoreLive.pipe( | 258 | const sourceCatalogStoreLayer = RuntimeSourceCatalogStoreLive.pipe( |
| 141 | Layer.provide(Layer.mergeAll(baseLayer, sourceStoreLayer)), | 259 | Layer.provide(Layer.mergeAll(baseLayer, sourceStoreLayer)), |
| 142 | ); | 260 | ); |
| @@ -203,73 +321,50 @@ export type ControlPlaneRuntime = { · 60 unmodified lines | |||
| 203 | close: () => Promise<void>; | 321 | close: () => Promise<void>; |
| 204 | }; | 322 | }; |
| 205 | 323 | ||
| 206 | export type CreateControlPlaneRuntimeOptions = RuntimeControlPlaneOptions; | ||
| 207 | |||
| 208 | export const provideControlPlaneRuntime = <A, E, R>( | 324 | export const provideControlPlaneRuntime = <A, E, R>( |
| 209 | effect: Effect.Effect<A, E, R>, | 325 | effect: Effect.Effect<A, E, R>, |
| 210 | runtime: ControlPlaneRuntime, | 326 | runtime: ControlPlaneRuntime, |
| 211 | ): Effect.Effect<A, E | never, any> => | 327 | ): Effect.Effect<A, E | never, never> => |
| 212 | effect.pipe(Effect.provide(runtime.managedRuntime)); | 328 | effect.pipe(Effect.provide(runtime.managedRuntime)); |
| 213 | 329 | ||
| 214 | export const createControlPlaneRuntime = ( | 330 | export const createControlPlaneRuntimeFromServices = (input: { |
| 215 | options: CreateControlPlaneRuntimeOptions, | 331 | services: RuntimeControlPlaneServices; |
| 216 | ): Effect.Effect<ControlPlaneRuntime, Error> => | 332 | } & RuntimeControlPlaneOptions): Effect.Effect<ControlPlaneRuntime, Error> => |
| 217 | (Effect.gen(function* () { | 333 | (Effect.gen(function* () { |
| 218 | const scope = yield* Scope.make(); | 334 | const localInstallation = yield* input.services.installationStore |
| 335 | .getOrProvision() | ||
| 336 | .pipe(Effect.mapError(toRuntimeBootstrapError)); | ||
| 219 | 337 | ||
| 220 | const localWorkspaceContext = yield* resolveLocalWorkspaceContext({ | 338 | const loadedLocalConfig = yield* input.services.workspaceConfigStore |
| 221 | workspaceRoot: options.workspaceRoot, | 339 | .load() |
| 222 | homeConfigPath: options.homeConfigPath, | 340 | .pipe(Effect.mapError(toRuntimeBootstrapError)); |
| 223 | homeStateDirectory: options.homeStateDirectory, | ||
| 224 | }).pipe( | ||
| 225 | Effect.mapError(toLocalRuntimeBootstrapError), | ||
| 226 | Effect.catchAll((error) => | ||
| 227 | closeScope(scope).pipe(Effect.zipRight(Effect.fail(error))), | ||
| 228 | ), | ||
| 229 | ); | ||
| 230 | |||
| 231 | const installationStore = LocalInstallationStore; | ||
| 232 | const workspaceConfigStore = LocalWorkspaceConfigStore; | ||
| 233 | const fileSystem = yield* FileSystem.FileSystem; | ||
| 234 | |||
| 235 | const localInstallation = yield* installationStore | ||
| 236 | .getOrProvision({ | ||
| 237 | context: localWorkspaceContext, | ||
| 238 | }) | ||
| 239 | .pipe( | ||
| 240 | Effect.mapError(toLocalRuntimeBootstrapError), | ||
| 241 | Effect.catchAll((error) => | ||
| 242 | closeScope(scope).pipe(Effect.zipRight(Effect.fail(error))), | ||
| 243 | ), | ||
| 244 | ); | ||
| 245 | |||
| 246 | const persistence = createLocalControlPlanePersistence( | ||
| 247 | localWorkspaceContext, | ||
| 248 | fileSystem, | ||
| 249 | ); | ||
| 250 | const rows = persistence.rows; | ||
| 251 | |||
| 252 | const loadedLocalConfig = yield* workspaceConfigStore | ||
| 253 | .load(localWorkspaceContext) | ||
| 254 | .pipe( | ||
| 255 | Effect.mapError(toLocalRuntimeBootstrapError), | ||
| 256 | Effect.catchAll((error) => | ||
| 257 | closeScope(scope).pipe(Effect.zipRight(Effect.fail(error))), | ||
| 258 | ), | ||
| 259 | ); | ||
| 260 | 341 | ||
| 261 | const effectiveLocalConfig = yield* synchronizeLocalWorkspaceState({ | 342 | const effectiveLocalConfig = yield* synchronizeLocalWorkspaceState({ |
| 262 | context: localWorkspaceContext, | 343 | context: input.services.workspaceContext, |
| 263 | loadedConfig: loadedLocalConfig, | 344 | loadedConfig: loadedLocalConfig, |
| 264 | }).pipe( | 345 | }) |
| 265 | Effect.mapError(toLocalRuntimeBootstrapError), | 346 | .pipe( |
| 266 | Effect.catchAll((error) => | 347 | Effect.provide( |
| 267 | closeScope(scope).pipe(Effect.zipRight(Effect.fail(error))), | 348 | makeLocalStorageLayer({ |
| 268 | ), | 349 | installationStore: toInstallationStoreShape( |
| 269 | ); | 350 | input.services.installationStore, |
| 351 | ), | ||
| 352 | workspaceConfigStore: toWorkspaceConfigStoreShape( | ||
| 353 | input.services.workspaceConfigStore, | ||
| 354 | ), | ||
| 355 | workspaceStateStore: toWorkspaceStateStoreShape( | ||
| 356 | input.services.workspaceStateStore, | ||
| 357 | ), | ||
| 358 | sourceArtifactStore: toSourceArtifactStoreShape( | ||
| 359 | input.services.sourceArtifactStore, | ||
| 360 | ), | ||
| 361 | }), | ||
| 362 | ), | ||
| 363 | ) | ||
| 364 | .pipe(Effect.mapError(toRuntimeBootstrapError)); | ||
| 270 | 365 | ||
| 271 | const runtimeLocalWorkspaceState: RuntimeLocalWorkspaceState = { | 366 | const runtimeLocalWorkspaceState: RuntimeLocalWorkspaceState = { |
| 272 | context: localWorkspaceContext, | 367 | context: input.services.workspaceContext, |
| 273 | installation: { | 368 | installation: { |
| 274 | workspaceId: localInstallation.workspaceId, | 369 | workspaceId: localInstallation.workspaceId, |
| 275 | accountId: localInstallation.accountId, | 370 | accountId: localInstallation.accountId, |
| @@ -282,8 +377,9 @@ export const createControlPlaneRuntime = ( · 6 unmodified lines | |||
| 282 | const liveExecutionManager = createLiveExecutionManager(); | 377 | const liveExecutionManager = createLiveExecutionManager(); |
| 283 | 378 | ||
| 284 | const concreteRuntimeLayer = createRuntimeControlPlaneLayer({ | 379 | const concreteRuntimeLayer = createRuntimeControlPlaneLayer({ |
| 285 | ...options, | 380 | ...input, |
| 286 | store: rows, | 381 | ...input.services, |
| 382 | store: input.services.persistence.rows, | ||
| 287 | localWorkspaceState: runtimeLocalWorkspaceState, | 383 | localWorkspaceState: runtimeLocalWorkspaceState, |
| 288 | liveExecutionManager, | 384 | liveExecutionManager, |
| 289 | }); | 385 | }); |
| @@ -298,7 +394,7 @@ export const createControlPlaneRuntime = ( · 8 unmodified lines | |||
| 298 | ); | 394 | ); |
| 299 | 395 | ||
| 300 | return { | 396 | return { |
| 301 | persistence, | 397 | persistence: input.services.persistence, |
| 302 | localInstallation, | 398 | localInstallation, |
| 303 | managedRuntime, | 399 | managedRuntime, |
| 304 | runtimeLayer: concreteRuntimeLayer as RuntimeControlPlaneLayer, | 400 | runtimeLayer: concreteRuntimeLayer as RuntimeControlPlaneLayer, |
| @@ -307,9 +403,7 @@ export const createControlPlaneRuntime = ( · 2 unmodified lines | |||
| 307 | () => undefined, | 403 | () => undefined, |
| 308 | ); | 404 | ); |
| 309 | await managedRuntime.dispose().catch(() => undefined); | 405 | await managedRuntime.dispose().catch(() => undefined); |
| 406 | await input.services.persistence.close().catch(() => undefined); | ||
| 310 | }, | 407 | }, |
| 311 | }; | 408 | }; |
| 312 | }).pipe(Effect.provide(NodeFileSystem.layer)) as Effect.Effect< | 409 | }) as Effect.Effect<ControlPlaneRuntime, Error>); |
| 313 | ControlPlaneRuntime, | ||
| 314 | Error | ||
| 315 | >); | ||
| @@ -5,7 +5,7 @@ import { NodeFileSystem } from "@effect/platform-node"; · 4 unmodified lines | |||
| 5 | import { describe, expect, it } from "@effect/vitest"; | 5 | import { describe, expect, it } from "@effect/vitest"; |
| 6 | import * as Effect from "effect/Effect"; | 6 | import * as Effect from "effect/Effect"; |
| 7 | 7 | ||
| 8 | import { createControlPlaneRuntime } from "../index"; | 8 | import { createLocalControlPlaneRuntime as createControlPlaneRuntime } from "../../../../sdk-file/src/index"; |
| 9 | import { getOrProvisionLocalInstallation } from "./installation"; | 9 | import { getOrProvisionLocalInstallation } from "./installation"; |
| 10 | import { resolveLocalWorkspaceContext } from "./config"; | 10 | import { resolveLocalWorkspaceContext } from "./config"; |
| 11 | 11 | ||
| @@ -38,10 +38,10 @@ import type { Source } from "#schema"; · 37 unmodified lines | |||
| 38 | export type InstallationStoreShape = { | 38 | export type InstallationStoreShape = { |
| 39 | load: ( | 39 | load: ( |
| 40 | context: ResolvedLocalWorkspaceContext, | 40 | context: ResolvedLocalWorkspaceContext, |
| 41 | ) => Effect.Effect<LocalInstallation, never, never>; | 41 | ) => Effect.Effect<LocalInstallation, Error, never>; |
| 42 | getOrProvision: (input: { | 42 | getOrProvision: (input: { |
| 43 | context: ResolvedLocalWorkspaceContext; | 43 | context: ResolvedLocalWorkspaceContext; |
| 44 | }) => Effect.Effect<LocalInstallation, never, never>; | 44 | }) => Effect.Effect<LocalInstallation, Error, never>; |
| 45 | }; | 45 | }; |
| 46 | 46 | ||
| 47 | export class InstallationStore extends Context.Tag( | 47 | export class InstallationStore extends Context.Tag( |
| @@ -22,10 +22,10 @@ import * as Schema from "effect/Schema"; · 21 unmodified lines | |||
| 22 | import type { RuntimeLocalWorkspaceState } from "../local/runtime-context"; | 22 | import type { RuntimeLocalWorkspaceState } from "../local/runtime-context"; |
| 23 | import { | 23 | import { |
| 24 | type LocalStorageServices, | 24 | type LocalStorageServices, |
| 25 | LocalInstallationStore, | 25 | type InstallationStoreShape, |
| 26 | LocalSourceArtifactStore, | 26 | type SourceArtifactStoreShape, |
| 27 | LocalWorkspaceConfigStore, | 27 | type WorkspaceConfigStoreShape, |
| 28 | LocalWorkspaceStateStore, | 28 | type WorkspaceStateStoreShape, |
| 29 | makeLocalStorageLayer, | 29 | makeLocalStorageLayer, |
| 30 | } from "../local/storage"; | 30 | } from "../local/storage"; |
| 31 | import { provideOptionalRuntimeLocalWorkspace } from "../local/runtime-context"; | 31 | import { provideOptionalRuntimeLocalWorkspace } from "../local/runtime-context"; |
| @@ -34,14 +34,15 @@ import { runtimeEffectError } from "../effect-errors"; · 2 unmodified lines | |||
| 34 | /** Run an Effect as a Promise, preserving the original error (not FiberFailure). */ | 34 | /** Run an Effect as a Promise, preserving the original error (not FiberFailure). */ |
| 35 | const runEffect = async <A>( | 35 | const runEffect = async <A>( |
| 36 | effect: Effect.Effect<A, unknown, LocalStorageServices>, | 36 | effect: Effect.Effect<A, unknown, LocalStorageServices>, |
| 37 | storage: { | ||
| 38 | installationStore: InstallationStoreShape; | ||
| 39 | workspaceConfigStore: WorkspaceConfigStoreShape; | ||
| 40 | workspaceStateStore: WorkspaceStateStoreShape; | ||
| 41 | sourceArtifactStore: SourceArtifactStoreShape; | ||
| 42 | }, | ||
| 37 | runtimeLocalWorkspace: RuntimeLocalWorkspaceState | null = null, | 43 | runtimeLocalWorkspace: RuntimeLocalWorkspaceState | null = null, |
| 38 | ): Promise<A> => { | 44 | ): Promise<A> => { |
| 39 | const baseLayer = makeLocalStorageLayer({ | 45 | const baseLayer = makeLocalStorageLayer(storage); |
| 40 | installationStore: LocalInstallationStore, | ||
| 41 | workspaceConfigStore: LocalWorkspaceConfigStore, | ||
| 42 | workspaceStateStore: LocalWorkspaceStateStore, | ||
| 43 | sourceArtifactStore: LocalSourceArtifactStore, | ||
| 44 | }); | ||
| 45 | const exit = await Effect.runPromiseExit( | 46 | const exit = await Effect.runPromiseExit( |
| 46 | provideOptionalRuntimeLocalWorkspace( | 47 | provideOptionalRuntimeLocalWorkspace( |
| 47 | effect.pipe(Effect.provide(baseLayer)), | 48 | effect.pipe(Effect.provide(baseLayer)), |
| @@ -314,6 +315,10 @@ export const createExecutorToolMap = (input: { · 266 unmodified lines | |||
| 314 | workspaceId: WorkspaceId; | 315 | workspaceId: WorkspaceId; |
| 315 | accountId: AccountId; | 316 | accountId: AccountId; |
| 316 | sourceAuthService: RuntimeSourceAuthService; | 317 | sourceAuthService: RuntimeSourceAuthService; |
| 318 | installationStore: InstallationStoreShape; | ||
| 319 | workspaceConfigStore: WorkspaceConfigStoreShape; | ||
| 320 | workspaceStateStore: WorkspaceStateStoreShape; | ||
| 321 | sourceArtifactStore: SourceArtifactStoreShape; | ||
| 317 | runtimeLocalWorkspace: RuntimeLocalWorkspaceState | null; | 322 | runtimeLocalWorkspace: RuntimeLocalWorkspaceState | null; |
| 318 | }): ToolMap => ({ | 323 | }): ToolMap => ({ |
| 319 | "executor.sources.add": toTool({ | 324 | "executor.sources.add": toTool({ |
| @@ -349,6 +354,12 @@ export const createExecutorToolMap = (input: { · 29 unmodified lines | |||
| 349 | } | 354 | } |
| 350 | : undefined, | 355 | : undefined, |
| 351 | ), | 356 | ), |
| 357 | { | ||
| 358 | installationStore: input.installationStore, | ||
| 359 | workspaceConfigStore: input.workspaceConfigStore, | ||
| 360 | workspaceStateStore: input.workspaceStateStore, | ||
| 361 | sourceArtifactStore: input.sourceArtifactStore, | ||
| 362 | }, | ||
| 352 | input.runtimeLocalWorkspace, | 363 | input.runtimeLocalWorkspace, |
| 353 | ); | 364 | ); |
| 354 | 365 | ||
| @@ -382,6 +393,12 @@ export const createExecutorToolMap = (input: { · 27 unmodified lines | |||
| 382 | invocation: context?.invocation, | 393 | invocation: context?.invocation, |
| 383 | onElicitation: context?.onElicitation, | 394 | onElicitation: context?.onElicitation, |
| 384 | }), | 395 | }), |
| 396 | { | ||
| 397 | installationStore: input.installationStore, | ||
| 398 | workspaceConfigStore: input.workspaceConfigStore, | ||
| 399 | workspaceStateStore: input.workspaceStateStore, | ||
| 400 | sourceArtifactStore: input.sourceArtifactStore, | ||
| 401 | }, | ||
| 385 | input.runtimeLocalWorkspace, | 402 | input.runtimeLocalWorkspace, |
| 386 | ); | 403 | ); |
| 387 | 404 | ||
| @@ -412,6 +429,12 @@ export const createExecutorToolMap = (input: { · 24 unmodified lines | |||
| 412 | } | 429 | } |
| 413 | : undefined, | 430 | : undefined, |
| 414 | ), | 431 | ), |
| 432 | { | ||
| 433 | installationStore: input.installationStore, | ||
| 434 | workspaceConfigStore: input.workspaceConfigStore, | ||
| 435 | workspaceStateStore: input.workspaceStateStore, | ||
| 436 | sourceArtifactStore: input.sourceArtifactStore, | ||
| 437 | }, | ||
| 415 | input.runtimeLocalWorkspace, | 438 | input.runtimeLocalWorkspace, |
| 416 | ); | 439 | ); |
| 417 | 440 | ||
| @@ -456,6 +479,12 @@ export const createExecutorToolMap = (input: { · 38 unmodified lines | |||
| 456 | elicitationId: result.sessionId, | 479 | elicitationId: result.sessionId, |
| 457 | }, | 480 | }, |
| 458 | }), | 481 | }), |
| 482 | { | ||
| 483 | installationStore: input.installationStore, | ||
| 484 | workspaceConfigStore: input.workspaceConfigStore, | ||
| 485 | workspaceStateStore: input.workspaceStateStore, | ||
| 486 | sourceArtifactStore: input.sourceArtifactStore, | ||
| 487 | }, | ||
| 459 | input.runtimeLocalWorkspace, | 488 | input.runtimeLocalWorkspace, |
| 460 | ); | 489 | ); |
| 461 | 490 | ||
| @@ -469,6 +498,12 @@ export const createExecutorToolMap = (input: { · 7 unmodified lines | |||
| 469 | sourceId: result.source.id, | 498 | sourceId: result.source.id, |
| 470 | actorAccountId: input.accountId, | 499 | actorAccountId: input.accountId, |
| 471 | }), | 500 | }), |
| 501 | { | ||
| 502 | installationStore: input.installationStore, | ||
| 503 | workspaceConfigStore: input.workspaceConfigStore, | ||
| 504 | workspaceStateStore: input.workspaceStateStore, | ||
| 505 | sourceArtifactStore: input.sourceArtifactStore, | ||
| 506 | }, | ||
| 472 | input.runtimeLocalWorkspace, | 507 | input.runtimeLocalWorkspace, |
| 473 | ); | 508 | ); |
| 474 | return toSerializableValue(connected); | 509 | return toSerializableValue(connected); |
| @@ -2,7 +2,6 @@ export * from "./common"; · 1 unmodified line | |||
| 2 | export * from "./enums"; | 2 | export * from "./enums"; |
| 3 | export * from "./ids"; | 3 | export * from "./ids"; |
| 4 | 4 | ||
| 5 | export * from "./models/auth"; | ||
| 6 | export * from "./models/source"; | 5 | export * from "./models/source"; |
| 7 | export * from "./models/source-catalog"; | 6 | export * from "./models/source-catalog"; |
| 8 | export * from "./models/auth-artifact"; | 7 | export * from "./models/auth-artifact"; |
| @@ -1,29 +0,0 @@ | |||
| 1 | import { Schema } from "effect"; | ||
| 2 | |||
| 3 | import { TimestampMsSchema } from "../../common"; | ||
| 4 | import { AccountIdSchema } from "../../ids"; | ||
| 5 | import { PrincipalProviderSchema } from "./principal"; | ||
| 6 | |||
| 7 | export const AccountSchema = Schema.Struct({ | ||
| 8 | id: AccountIdSchema, | ||
| 9 | provider: PrincipalProviderSchema, | ||
| 10 | subject: Schema.String, | ||
| 11 | email: Schema.NullOr(Schema.String), | ||
| 12 | displayName: Schema.NullOr(Schema.String), | ||
| 13 | createdAt: TimestampMsSchema, | ||
| 14 | updatedAt: TimestampMsSchema, | ||
| 15 | }); | ||
| 16 | |||
| 17 | export const AccountInsertSchema = AccountSchema; | ||
| 18 | |||
| 19 | export const AccountUpdateSchema = Schema.partial( | ||
| 20 | Schema.Struct({ | ||
| 21 | provider: PrincipalProviderSchema, | ||
| 22 | subject: Schema.String, | ||
| 23 | email: Schema.NullOr(Schema.String), | ||
| 24 | displayName: Schema.NullOr(Schema.String), | ||
| 25 | updatedAt: TimestampMsSchema, | ||
| 26 | }), | ||
| 27 | ); | ||
| 28 | |||
| 29 | export type Account = typeof AccountSchema.Type; | ||
| @@ -1,2 +0,0 @@ | |||
| 1 | export * from "./account"; | ||
| 2 | export * from "./principal"; | ||
| @@ -1,20 +0,0 @@ | |||
| 1 | import { Schema } from "effect"; | ||
| 2 | |||
| 3 | import { AccountIdSchema } from "../../ids"; | ||
| 4 | |||
| 5 | export const PrincipalProviderSchema = Schema.Literal( | ||
| 6 | "local", | ||
| 7 | "workos", | ||
| 8 | "service", | ||
| 9 | ); | ||
| 10 | |||
| 11 | export const PrincipalSchema = Schema.Struct({ | ||
| 12 | accountId: AccountIdSchema, | ||
| 13 | provider: PrincipalProviderSchema, | ||
| 14 | subject: Schema.String, | ||
| 15 | email: Schema.NullOr(Schema.String), | ||
| 16 | displayName: Schema.NullOr(Schema.String), | ||
| 17 | }); | ||
| 18 | |||
| 19 | export type PrincipalProvider = typeof PrincipalProviderSchema.Type; | ||
| 20 | export type Principal = typeof PrincipalSchema.Type; | ||
| @@ -18,6 +18,7 @@ · 17 unmodified lines | |||
| 18 | "@executor/platform-api": "workspace:*", | 18 | "@executor/platform-api": "workspace:*", |
| 19 | "@executor/platform-internal": "workspace:*", | 19 | "@executor/platform-internal": "workspace:*", |
| 20 | "@executor/platform-sdk": "workspace:*", | 20 | "@executor/platform-sdk": "workspace:*", |
| 21 | "@executor/platform-sdk-file": "workspace:*", | ||
| 21 | "@opentelemetry/api": "^1.9.0", | 22 | "@opentelemetry/api": "^1.9.0", |
| 22 | "@opentelemetry/exporter-trace-otlp-grpc": "^0.213.0", | 23 | "@opentelemetry/exporter-trace-otlp-grpc": "^0.213.0", |
| 23 | "@opentelemetry/resources": "^2.6.0", | 24 | "@opentelemetry/resources": "^2.6.0", |
| @@ -9,12 +9,16 @@ import { Readable } from "node:stream"; · 8 unmodified lines | |||
| 9 | import { FileSystem, HttpApiBuilder, HttpServer } from "@effect/platform"; | 9 | import { FileSystem, HttpApiBuilder, HttpServer } from "@effect/platform"; |
| 10 | import { NodeFileSystem } from "@effect/platform-node"; | 10 | import { NodeFileSystem } from "@effect/platform-node"; |
| 11 | import { | 11 | import { |
| 12 | createControlPlaneApiLayer, | 12 | createExecutorApiLayer, |
| 13 | } from "@executor/platform-api"; | 13 | } from "@executor/platform-api"; |
| 14 | import { createExecutorMcpRequestHandler } from "@executor/executor-mcp"; | 14 | import { createExecutorMcpRequestHandler } from "@executor/executor-mcp"; |
| 15 | import { createExecutorAdminToolMap } from "@executor/platform-internal"; | 15 | import { createWorkspaceExecutorAdminToolMap } from "@executor/platform-internal"; |
| 16 | import { | ||
| 17 | createExecutorEffect, | ||
| 18 | type Executor, | ||
| 19 | } from "@executor/platform-sdk"; | ||
| 20 | import { createLocalExecutorBackend } from "@executor/platform-sdk-file"; | ||
| 16 | import { | 21 | import { |
| 17 | createControlPlaneRuntime, | ||
| 18 | type ResolveExecutionEnvironment, | 22 | type ResolveExecutionEnvironment, |
| 19 | type ResolveSecretMaterial, | 23 | type ResolveSecretMaterial, |
| 20 | type ControlPlaneRuntime, | 24 | type ControlPlaneRuntime, |
| @@ -71,6 +75,7 @@ type StaticUiOptions = { · 50 unmodified lines | |||
| 71 | }; | 75 | }; |
| 72 | 76 | ||
| 73 | export type LocalExecutorServer = { | 77 | export type LocalExecutorServer = { |
| 78 | readonly executor: Executor; | ||
| 74 | readonly runtime: ControlPlaneRuntime; | 79 | readonly runtime: ControlPlaneRuntime; |
| 75 | readonly port: number; | 80 | readonly port: number; |
| 76 | readonly host: string; | 81 | readonly host: string; |
| @@ -89,6 +94,7 @@ export type StartLocalExecutorServerOptions = { · 12 unmodified lines | |||
| 89 | }; | 94 | }; |
| 90 | 95 | ||
| 91 | export type LocalExecutorRequestHandler = { | 96 | export type LocalExecutorRequestHandler = { |
| 97 | readonly executor: Executor; | ||
| 92 | readonly runtime: ControlPlaneRuntime; | 98 | readonly runtime: ControlPlaneRuntime; |
| 93 | readonly handleApiRequest: (request: Request) => Promise<Response>; | 99 | readonly handleApiRequest: (request: Request) => Promise<Response>; |
| 94 | readonly getBaseUrl: () => string | undefined; | 100 | readonly getBaseUrl: () => string | undefined; |
| @@ -102,25 +108,27 @@ const EXECUTOR_NPM_DIST_TAGS_PATHNAME = "/v1/app/npm/dist-tags"; · 7 unmodified lines | |||
| 102 | const EXECUTOR_NPM_DIST_TAGS_URL = | 108 | const EXECUTOR_NPM_DIST_TAGS_URL = |
| 103 | "https://registry.npmjs.org/-/package/executor/dist-tags"; | 109 | "https://registry.npmjs.org/-/package/executor/dist-tags"; |
| 104 | 110 | ||
| 105 | const disposeRuntime = (runtime: ControlPlaneRuntime) => | 111 | const disposeExecutor = (executor: Executor) => |
| 106 | Effect.tryPromise({ | 112 | Effect.tryPromise({ |
| 107 | try: () => runtime.close(), | 113 | try: () => executor.close(), |
| 108 | catch: (cause) => | 114 | catch: (cause) => |
| 109 | cause instanceof Error ? cause : new Error(String(cause ?? "runtime close failed")), | 115 | cause instanceof Error ? cause : new Error(String(cause ?? "executor close failed")), |
| 110 | }).pipe(Effect.orDie); | 116 | }).pipe(Effect.orDie); |
| 111 | 117 | ||
| 112 | const createRuntime = ( | 118 | const createExecutorRuntime = ( |
| 113 | localDataDir: string, | 119 | localDataDir: string, |
| 114 | getLocalServerBaseUrl: () => string | undefined, | 120 | getLocalServerBaseUrl: () => string | undefined, |
| 115 | options: StartLocalExecutorServerOptions, | 121 | options: StartLocalExecutorServerOptions, |
| 116 | ) => | 122 | ) => |
| 117 | createControlPlaneRuntime({ | 123 | createExecutorEffect({ |
| 118 | workspaceRoot: options.workspaceRoot, | 124 | backend: createLocalExecutorBackend({ |
| 125 | workspaceRoot: options.workspaceRoot, | ||
| 126 | localDataDir, | ||
| 127 | }), | ||
| 119 | executionResolver: options.executionResolver, | 128 | executionResolver: options.executionResolver, |
| 120 | createInternalToolMap: createExecutorAdminToolMap, | 129 | createInternalToolMap: createWorkspaceExecutorAdminToolMap, |
| 121 | resolveSecretMaterial: options.resolveSecretMaterial, | 130 | resolveSecretMaterial: options.resolveSecretMaterial, |
| 122 | getLocalServerBaseUrl, | 131 | getLocalServerBaseUrl, |
| 123 | localDataDir, | ||
| 124 | }).pipe( | 132 | }).pipe( |
| 125 | Effect.mapError((cause) => | 133 | Effect.mapError((cause) => |
| 126 | cause instanceof Error ? cause : new Error(String(cause)), | 134 | cause instanceof Error ? cause : new Error(String(cause)), |
| @@ -128,7 +136,7 @@ const createRuntime = ( · 1 unmodified line | |||
| 128 | ); | 136 | ); |
| 129 | 137 | ||
| 130 | const createControlPlaneWebHandler = ( | 138 | const createControlPlaneWebHandler = ( |
| 131 | runtime: ControlPlaneRuntime, | 139 | executor: Executor, |
| 132 | tracingRuntime: ReturnType<typeof createLocalTracingRuntimeFromEnv>, | 140 | tracingRuntime: ReturnType<typeof createLocalTracingRuntimeFromEnv>, |
| 133 | ) => | 141 | ) => |
| 134 | Effect.acquireRelease( | 142 | Effect.acquireRelease( |
| @@ -137,7 +145,7 @@ const createControlPlaneWebHandler = ( · 2 unmodified lines | |||
| 137 | Layer.merge( | 145 | Layer.merge( |
| 138 | HttpApiBuilder.middlewareOpenApi({ path: "/v1/openapi.json" }).pipe( | 146 | HttpApiBuilder.middlewareOpenApi({ path: "/v1/openapi.json" }).pipe( |
| 139 | Layer.provideMerge( | 147 | Layer.provideMerge( |
| 140 | createControlPlaneApiLayer(runtime.runtimeLayer).pipe( | 148 | createExecutorApiLayer(executor).pipe( |
| 141 | Layer.provideMerge(tracingRuntime?.layer ?? Layer.empty), | 149 | Layer.provideMerge(tracingRuntime?.layer ?? Layer.empty), |
| 142 | ), | 150 | ), |
| 143 | ) | 151 | ) |
| @@ -369,14 +377,17 @@ export const createLocalExecutorRequestHandler = ( · 225 unmodified lines | |||
| 369 | }); | 377 | }); |
| 370 | } | 378 | } |
| 371 | 379 | ||
| 372 | const runtime = yield* Effect.acquireRelease( | 380 | const executor = yield* Effect.acquireRelease( |
| 373 | createRuntime(requestedLocalDataDir, () => baseUrlRef, options), | 381 | createExecutorRuntime(requestedLocalDataDir, () => baseUrlRef, options), |
| 374 | disposeRuntime, | 382 | disposeExecutor, |
| 375 | ); | 383 | ); |
| 376 | 384 | ||
| 377 | const apiHandler = yield* createControlPlaneWebHandler(runtime, tracingRuntime); | 385 | const apiHandler = yield* createControlPlaneWebHandler( |
| 386 | executor, | ||
| 387 | tracingRuntime, | ||
| 388 | ); | ||
| 378 | const mcpHandler = yield* Effect.acquireRelease( | 389 | const mcpHandler = yield* Effect.acquireRelease( |
| 379 | Effect.sync(() => createExecutorMcpRequestHandler(runtime)), | 390 | Effect.sync(() => createExecutorMcpRequestHandler(executor.runtime)), |
| 380 | (handler: ExecutorMcpHandler) => | 391 | (handler: ExecutorMcpHandler) => |
| 381 | Effect.tryPromise({ | 392 | Effect.tryPromise({ |
| 382 | try: () => handler.close(), | 393 | try: () => handler.close(), |
| @@ -388,7 +399,8 @@ export const createLocalExecutorRequestHandler = ( · 5 unmodified lines | |||
| 388 | ); | 399 | ); |
| 389 | 400 | ||
| 390 | return { | 401 | return { |
| 391 | runtime, | 402 | executor, |
| 403 | runtime: executor.runtime, | ||
| 392 | handleApiRequest: (request) => { | 404 | handleApiRequest: (request) => { |
| 393 | const pathname = new URL(request.url).pathname; | 405 | const pathname = new URL(request.url).pathname; |
| 394 | if (pathname === EXECUTOR_NPM_DIST_TAGS_PATHNAME) { | 406 | if (pathname === EXECUTOR_NPM_DIST_TAGS_PATHNAME) { |
| @@ -465,6 +477,7 @@ export const createLocalExecutorServer = ( · 70 unmodified lines | |||
| 465 | requestHandler.setBaseUrl(baseUrl); | 477 | requestHandler.setBaseUrl(baseUrl); |
| 466 | 478 | ||
| 467 | return { | 479 | return { |
| 480 | executor: requestHandler.executor, | ||
| 468 | runtime: requestHandler.runtime, | 481 | runtime: requestHandler.runtime, |
| 469 | host, | 482 | host, |
| 470 | port: resolvedAddress.port, | 483 | port: resolvedAddress.port, |