Unified · Split
| @@ -1,22 +1,117 @@ | |||
| 1 | { | 1 | { |
| 2 | "sources": { | 2 | "sources": { |
| 3 | "github": { | 3 | "github": { |
| 4 | "kind": "openapi", | ||
| 5 | "name": "GitHub", | 4 | "name": "GitHub", |
| 6 | "connection": { | 5 | "connection": { |
| 7 | "endpoint": "https://api.github.com/" | 6 | "endpoint": "https://api.github.com" |
| 8 | }, | 7 | }, |
| 8 | "kind": "openapi", | ||
| 9 | "binding": { | 9 | "binding": { |
| 10 | "specUrl": "https://raw.githubusercontent.com/github/rest-api-description/main/descriptions/api.github.com/api.github.com.json", | 10 | "specUrl": "https://example.com/github-openapi.yaml", |
| 11 | "defaultHeaders": null | 11 | "defaultHeaders": null |
| 12 | } | 12 | } |
| 13 | } | 13 | }, |
| 14 | }, | 14 | "googleapis": { |
| 15 | "policies": { | 15 | "name": "Drive", |
| 16 | "demo.*": { | 16 | "namespace": "google.drive", |
| 17 | "match": "demo.*", | 17 | "connection": { |
| 18 | "action": "allow", | 18 | "endpoint": "http://127.0.0.1:60144/drive/$discovery/rest?version=v3" |
| 19 | "approval": "auto" | 19 | }, |
| 20 | "kind": "google_discovery", | ||
| 21 | "binding": { | ||
| 22 | "service": "drive", | ||
| 23 | "version": "v3", | ||
| 24 | "discoveryUrl": "http://127.0.0.1:60144/drive/$discovery/rest?version=v3", | ||
| 25 | "defaultHeaders": null, | ||
| 26 | "scopes": [ | ||
| 27 | "scope:drive.readonly" | ||
| 28 | ] | ||
| 29 | } | ||
| 30 | }, | ||
| 31 | "google-gmail": { | ||
| 32 | "name": "Gmail", | ||
| 33 | "namespace": "google.gmail", | ||
| 34 | "connection": { | ||
| 35 | "endpoint": "http://127.0.0.1:60197/gmail/$discovery/rest?version=v1" | ||
| 36 | }, | ||
| 37 | "kind": "google_discovery", | ||
| 38 | "binding": { | ||
| 39 | "service": "gmail", | ||
| 40 | "version": "v1", | ||
| 41 | "discoveryUrl": "http://127.0.0.1:60197/gmail/$discovery/rest?version=v1", | ||
| 42 | "defaultHeaders": null, | ||
| 43 | "scopes": [ | ||
| 44 | "scope:gmail.readonly" | ||
| 45 | ] | ||
| 46 | } | ||
| 47 | }, | ||
| 48 | "google-calendar": { | ||
| 49 | "name": "Calendar", | ||
| 50 | "namespace": "google.calendar", | ||
| 51 | "connection": { | ||
| 52 | "endpoint": "http://127.0.0.1:60190/calendar/$discovery/rest?version=v3" | ||
| 53 | }, | ||
| 54 | "kind": "google_discovery", | ||
| 55 | "binding": { | ||
| 56 | "service": "calendar", | ||
| 57 | "version": "v3", | ||
| 58 | "discoveryUrl": "http://127.0.0.1:60190/calendar/$discovery/rest?version=v3", | ||
| 59 | "defaultHeaders": null, | ||
| 60 | "scopes": [ | ||
| 61 | "scope:calendar.readonly" | ||
| 62 | ] | ||
| 63 | } | ||
| 64 | }, | ||
| 65 | "google-drive": { | ||
| 66 | "name": "Drive", | ||
| 67 | "namespace": "google.drive", | ||
| 68 | "connection": { | ||
| 69 | "endpoint": "http://127.0.0.1:60205/drive/$discovery/rest?version=v3" | ||
| 70 | }, | ||
| 71 | "kind": "google_discovery", | ||
| 72 | "binding": { | ||
| 73 | "service": "drive", | ||
| 74 | "version": "v3", | ||
| 75 | "discoveryUrl": "http://127.0.0.1:60205/drive/$discovery/rest?version=v3", | ||
| 76 | "defaultHeaders": null, | ||
| 77 | "scopes": [ | ||
| 78 | "scope:drive.readonly" | ||
| 79 | ] | ||
| 80 | } | ||
| 81 | }, | ||
| 82 | "google-drive-2": { | ||
| 83 | "name": "Drive", | ||
| 84 | "namespace": "google.drive", | ||
| 85 | "connection": { | ||
| 86 | "endpoint": "https://example.test/drive/$discovery/rest?version=v3" | ||
| 87 | }, | ||
| 88 | "kind": "google_discovery", | ||
| 89 | "binding": { | ||
| 90 | "service": "drive", | ||
| 91 | "version": "v3", | ||
| 92 | "discoveryUrl": "https://example.test/drive/$discovery/rest?version=v3", | ||
| 93 | "defaultHeaders": null, | ||
| 94 | "scopes": [ | ||
| 95 | "scope:drive.readonly" | ||
| 96 | ] | ||
| 97 | } | ||
| 98 | }, | ||
| 99 | "google-gmail-2": { | ||
| 100 | "kind": "google_discovery", | ||
| 101 | "name": "Gmail", | ||
| 102 | "namespace": "google.gmail", | ||
| 103 | "connection": { | ||
| 104 | "endpoint": "https://example.test/gmail/$discovery/rest?version=v1" | ||
| 105 | }, | ||
| 106 | "binding": { | ||
| 107 | "service": "gmail", | ||
| 108 | "version": "v1", | ||
| 109 | "discoveryUrl": "https://example.test/gmail/$discovery/rest?version=v1", | ||
| 110 | "defaultHeaders": null, | ||
| 111 | "scopes": [ | ||
| 112 | "scope:gmail.readonly" | ||
| 113 | ] | ||
| 114 | } | ||
| 20 | } | 115 | } |
| 21 | } | 116 | } |
| 22 | } | 117 | } |
| @@ -43,6 +43,8 @@ · 42 unmodified lines | |||
| 43 | "executor-monorepo/no-cross-workspace-relative-imports": "error", | 43 | "executor-monorepo/no-cross-workspace-relative-imports": "error", |
| 44 | "executor-monorepo/no-direct-effect-tag-read": "error", | 44 | "executor-monorepo/no-direct-effect-tag-read": "error", |
| 45 | "executor-monorepo/no-effect-run-in-effect-vitest-tests": "error", | 45 | "executor-monorepo/no-effect-run-in-effect-vitest-tests": "error", |
| 46 | "executor-monorepo/no-manual-httpapi-openapi-bridge": "error", | ||
| 47 | "executor-monorepo/no-manual-openapi-documents": "error", | ||
| 46 | "executor-monorepo/no-node-fs-with-effect-imports": "error", | 48 | "executor-monorepo/no-node-fs-with-effect-imports": "error", |
| 47 | "executor-monorepo/no-raw-effect-fail-errors": "error", | 49 | "executor-monorepo/no-raw-effect-fail-errors": "error", |
| 48 | "executor-monorepo/no-yield-effect-fail": "error", | 50 | "executor-monorepo/no-yield-effect-fail": "error", |
| @@ -50,6 +52,17 @@ · 1 unmodified line | |||
| 50 | }, | 52 | }, |
| 51 | 53 | ||
| 52 | "overrides": [ | 54 | "overrides": [ |
| 55 | { | ||
| 56 | // SDK tests still use relative workspace imports to avoid introducing | ||
| 57 | // package-graph cycles from test-only dependencies. | ||
| 58 | "files": [ | ||
| 59 | "packages/platform/sdk/src/executor.test.ts", | ||
| 60 | "packages/platform/sdk/src/runtime/executor-runtime.test.ts" | ||
| 61 | ], | ||
| 62 | "rules": { | ||
| 63 | "executor-monorepo/no-cross-workspace-relative-imports": "off" | ||
| 64 | } | ||
| 65 | }, | ||
| 53 | { | 66 | { |
| 54 | // JSON Schema conditionals legitimately use a `then` key. | 67 | // JSON Schema conditionals legitimately use a `then` key. |
| 55 | "files": [ | 68 | "files": [ |
| @@ -0,0 +1,30 @@ | |||
| 1 | import { HttpApi, HttpApiBuilder, HttpApiEndpoint, HttpApiGroup, HttpApiSchema } from '@effect/platform'; | ||
| 2 | import { startOpenApiTestServer } from '@executor/effect-test-utils'; | ||
| 3 | import * as Effect from 'effect/Effect'; | ||
| 4 | import * as Layer from 'effect/Layer'; | ||
| 5 | import * as Schema from 'effect/Schema'; | ||
| 6 | |||
| 7 | const ownerParam = HttpApiSchema.param('owner', Schema.String); | ||
| 8 | const repoParam = HttpApiSchema.param('repo', Schema.String); | ||
| 9 | class DemoReposApi extends HttpApiGroup.make('repos').add( | ||
| 10 | HttpApiEndpoint.get('getRepo')`/repos/${ownerParam}/${repoParam}`.addSuccess( | ||
| 11 | Schema.Struct({ full_name: Schema.String, private: Schema.Boolean }), | ||
| 12 | ), | ||
| 13 | ) {} | ||
| 14 | class DemoApi extends HttpApi.make('demo').add(DemoReposApi) {} | ||
| 15 | const live = HttpApiBuilder.group(DemoApi, 'repos', (handlers) => | ||
| 16 | handlers.handle('getRepo', ({ path, request }) => { | ||
| 17 | console.log('auth', request.headers.authorization); | ||
| 18 | return Effect.succeed({ full_name: `${path.owner}/${path.repo}`, private: false }); | ||
| 19 | }), | ||
| 20 | ); | ||
| 21 | const main = async () => { | ||
| 22 | const server = await startOpenApiTestServer({ apiLayer: HttpApiBuilder.api(DemoApi).pipe(Layer.provide(live)) }); | ||
| 23 | console.log('base', server.baseUrl, server.specUrl); | ||
| 24 | const spec = await fetch(server.specUrl); | ||
| 25 | console.log('spec', spec.status, await spec.text()); | ||
| 26 | const resp = await fetch(`${server.baseUrl}/repos/vercel/ai`, { headers: { authorization: 'Bearer test' } }); | ||
| 27 | console.log('repo', resp.status, await resp.text()); | ||
| 28 | await server.close(); | ||
| 29 | }; | ||
| 30 | main().catch((e) => { console.error(e); process.exit(1); }); | ||
| @@ -0,0 +1,7 @@ | |||
| 1 | # Repo Agent Notes | ||
| 2 | |||
| 3 | - When a test needs an OpenAPI spec, generate it from Effect `HttpApi` with `OpenApi.fromApi(...)`. | ||
| 4 | - When a test needs to serve an Effect `HttpApi` plus `/openapi.json`, use `@executor/effect-test-utils` via `startOpenApiTestServer(...)` or `makeOpenApiTestServer(...)`. | ||
| 5 | - Do not hand-author inline OpenAPI documents in normal tests. | ||
| 6 | - Do not hand-roll `HttpApiBuilder.toWebHandler(...)` to Node HTTP bridges for OpenAPI test servers. | ||
| 7 | - Raw OpenAPI parser/import-fidelity tests are the exception; those may keep literal OpenAPI documents where the point of the test is the raw document itself. | ||
| @@ -45,6 +45,7 @@ · 44 unmodified lines | |||
| 45 | "effect": "catalog:" | 45 | "effect": "catalog:" |
| 46 | }, | 46 | }, |
| 47 | "devDependencies": { | 47 | "devDependencies": { |
| 48 | "@executor/effect-test-utils": "workspace:*", | ||
| 48 | "@executor/mcp-elicitation-demo": "workspace:*", | 49 | "@executor/mcp-elicitation-demo": "workspace:*", |
| 49 | "@executor/runtime-ses": "workspace:*", | 50 | "@executor/runtime-ses": "workspace:*", |
| 50 | "@effect/vitest": "catalog:", | 51 | "@effect/vitest": "catalog:", |
| @@ -1,5 +1,5 @@ | |||
| 1 | import type { ExecutorApiClient } from "@executor/platform-api"; | 1 | import type { ExecutorApiClient } from "@executor/platform-api"; |
| 2 | import { WorkspaceIdSchema } from "@executor/platform-sdk/schema"; | 2 | import { ScopeIdSchema } from "@executor/platform-sdk/schema"; |
| 3 | import * as Effect from "effect/Effect"; | 3 | import * as Effect from "effect/Effect"; |
| 4 | 4 | ||
| 5 | const readBindingString = (binding: Record<string, unknown>, key: string): string | null => | 5 | const readBindingString = (binding: Record<string, unknown>, key: string): string | null => |
| @@ -41,7 +41,7 @@ export const seedDemoMcpSourceInWorkspace = ( · 35 unmodified lines | |||
| 41 | input: SeedDemoMcpSourceInput, | 41 | input: SeedDemoMcpSourceInput, |
| 42 | ): Effect.Effect<SeedDemoMcpSourceResult, unknown, never> => | 42 | ): Effect.Effect<SeedDemoMcpSourceResult, unknown, never> => |
| 43 | Effect.gen(function* () { | 43 | Effect.gen(function* () { |
| 44 | const workspaceId = WorkspaceIdSchema.make(input.workspaceId); | 44 | const workspaceId = ScopeIdSchema.make(input.workspaceId); |
| 45 | 45 | ||
| 46 | const existing = yield* input.client.sources.list({ | 46 | const existing = yield* input.client.sources.list({ |
| 47 | path: { | 47 | path: { |
| @@ -138,7 +138,7 @@ export const seedGithubOpenApiSourceInWorkspace = ( · 90 unmodified lines | |||
| 138 | input: SeedGithubOpenApiSourceInput, | 138 | input: SeedGithubOpenApiSourceInput, |
| 139 | ): Effect.Effect<SeedDemoMcpSourceResult, unknown, never> => | 139 | ): Effect.Effect<SeedDemoMcpSourceResult, unknown, never> => |
| 140 | Effect.gen(function* () { | 140 | Effect.gen(function* () { |
| 141 | const workspaceId = WorkspaceIdSchema.make(input.workspaceId); | 141 | const workspaceId = ScopeIdSchema.make(input.workspaceId); |
| 142 | 142 | ||
| 143 | const existing = yield* input.client.sources.list({ | 143 | const existing = yield* input.client.sources.list({ |
| 144 | path: { | 144 | path: { |
| @@ -289,8 +289,8 @@ const loadRunWorkflowText = (): Effect.Effect<string, Error, never> => · 288 unmodified lines | |||
| 289 | const environment = yield* Effect.gen(function* () { | 289 | const environment = yield* Effect.gen(function* () { |
| 290 | const resolveExecutionEnvironment = yield* RuntimeExecutionResolverService; | 290 | const resolveExecutionEnvironment = yield* RuntimeExecutionResolverService; |
| 291 | return yield* resolveExecutionEnvironment({ | 291 | return yield* resolveExecutionEnvironment({ |
| 292 | workspaceId: executor.workspaceId, | 292 | scopeId: executor.scopeId, |
| 293 | accountId: executor.accountId, | 293 | actorScopeId: executor.actorScopeId, |
| 294 | executionId: ExecutionIdSchema.make("exec_help"), | 294 | executionId: ExecutionIdSchema.make("exec_help"), |
| 295 | }); | 295 | }); |
| 296 | }).pipe( | 296 | }).pipe( |
| @@ -403,7 +403,7 @@ const getLocalAuthedClient = (baseUrl: string = DEFAULT_SERVER_BASE_URL) => · 106 unmodified lines | |||
| 403 | const installation = yield* bootstrapClient.local.installation({}); | 403 | const installation = yield* bootstrapClient.local.installation({}); |
| 404 | const client = yield* createExecutorApiClient({ | 404 | const client = yield* createExecutorApiClient({ |
| 405 | baseUrl, | 405 | baseUrl, |
| 406 | accountId: installation.accountId, | 406 | accountId: installation.actorScopeId, |
| 407 | }); | 407 | }); |
| 408 | 408 | ||
| 409 | return { | 409 | return { |
| @@ -574,6 +574,10 @@ const getServerStatus = ( · 164 unmodified lines | |||
| 574 | const installation = reachable | 574 | const installation = reachable |
| 575 | ? yield* getBootstrapClient(baseUrl).pipe( | 575 | ? yield* getBootstrapClient(baseUrl).pipe( |
| 576 | Effect.flatMap((client) => client.local.installation({})), | 576 | Effect.flatMap((client) => client.local.installation({})), |
| 577 | Effect.map((installation) => ({ | ||
| 578 | accountId: installation.actorScopeId, | ||
| 579 | workspaceId: installation.scopeId, | ||
| 580 | })), | ||
| 577 | Effect.catchAll(() => Effect.succeed(null)), | 581 | Effect.catchAll(() => Effect.succeed(null)), |
| 578 | ) | 582 | ) |
| 579 | : null; | 583 | : null; |
| @@ -923,7 +927,7 @@ const promptInteraction = (input: { · 343 unmodified lines | |||
| 923 | 927 | ||
| 924 | const waitForExecutionProgress = (input: { | 928 | const waitForExecutionProgress = (input: { |
| 925 | client: ExecutorApiClient; | 929 | client: ExecutorApiClient; |
| 926 | workspaceId: ExecutionEnvelope["execution"]["workspaceId"]; | 930 | workspaceId: ExecutionEnvelope["execution"]["scopeId"]; |
| 927 | executionId: ExecutionEnvelope["execution"]["id"]; | 931 | executionId: ExecutionEnvelope["execution"]["id"]; |
| 928 | pendingInteractionId: ExecutionInteraction["id"]; | 932 | pendingInteractionId: ExecutionInteraction["id"]; |
| 929 | }) => | 933 | }) => |
| @@ -987,7 +991,7 @@ const seedDemoMcpSource = (input: { · 57 unmodified lines | |||
| 987 | const { installation, client } = yield* getLocalAuthedClient(input.baseUrl); | 991 | const { installation, client } = yield* getLocalAuthedClient(input.baseUrl); |
| 988 | const result = yield* seedDemoMcpSourceInWorkspace({ | 992 | const result = yield* seedDemoMcpSourceInWorkspace({ |
| 989 | client, | 993 | client, |
| 990 | workspaceId: installation.workspaceId, | 994 | workspaceId: installation.scopeId, |
| 991 | endpoint: input.endpoint, | 995 | endpoint: input.endpoint, |
| 992 | name: input.name, | 996 | name: input.name, |
| 993 | namespace: input.namespace, | 997 | namespace: input.namespace, |
| @@ -1011,7 +1015,7 @@ const seedGithubOpenApiSource = (input: { · 17 unmodified lines | |||
| 1011 | const { installation, client } = yield* getLocalAuthedClient(input.baseUrl); | 1015 | const { installation, client } = yield* getLocalAuthedClient(input.baseUrl); |
| 1012 | const result = yield* seedGithubOpenApiSourceInWorkspace({ | 1016 | const result = yield* seedGithubOpenApiSourceInWorkspace({ |
| 1013 | client, | 1017 | client, |
| 1014 | workspaceId: installation.workspaceId, | 1018 | workspaceId: installation.scopeId, |
| 1015 | endpoint: input.endpoint, | 1019 | endpoint: input.endpoint, |
| 1016 | specUrl: input.specUrl, | 1020 | specUrl: input.specUrl, |
| 1017 | name: input.name, | 1021 | name: input.name, |
| @@ -1026,7 +1030,7 @@ const seedGithubOpenApiSource = (input: { · 8 unmodified lines | |||
| 1026 | 1030 | ||
| 1027 | const driveExecution = (input: { | 1031 | const driveExecution = (input: { |
| 1028 | client: ExecutorApiClient; | 1032 | client: ExecutorApiClient; |
| 1029 | workspaceId: ExecutionEnvelope["execution"]["workspaceId"]; | 1033 | workspaceId: ExecutionEnvelope["execution"]["scopeId"]; |
| 1030 | envelope: ExecutionEnvelope; | 1034 | envelope: ExecutionEnvelope; |
| 1031 | baseUrl: string; | 1035 | baseUrl: string; |
| 1032 | shouldOpenUrls: boolean; | 1036 | shouldOpenUrls: boolean; |
| @@ -1297,7 +1301,7 @@ const callCommand = Command.make( · 264 unmodified lines | |||
| 1297 | const { installation, client } = yield* getLocalAuthedClient(baseUrl); | 1301 | const { installation, client } = yield* getLocalAuthedClient(baseUrl); |
| 1298 | const created = yield* client.executions.create({ | 1302 | const created = yield* client.executions.create({ |
| 1299 | path: { | 1303 | path: { |
| 1300 | workspaceId: installation.workspaceId, | 1304 | workspaceId: installation.scopeId, |
| 1301 | }, | 1305 | }, |
| 1302 | payload: { | 1306 | payload: { |
| 1303 | code: resolvedCode, | 1307 | code: resolvedCode, |
| @@ -1307,7 +1311,7 @@ const callCommand = Command.make( · 3 unmodified lines | |||
| 1307 | 1311 | ||
| 1308 | const settled = yield* driveExecution({ | 1312 | const settled = yield* driveExecution({ |
| 1309 | client, | 1313 | client, |
| 1310 | workspaceId: installation.workspaceId, | 1314 | workspaceId: installation.scopeId, |
| 1311 | envelope: created, | 1315 | envelope: created, |
| 1312 | baseUrl, | 1316 | baseUrl, |
| 1313 | shouldOpenUrls: !noOpen, | 1317 | shouldOpenUrls: !noOpen, |
| @@ -1333,14 +1337,14 @@ const resumeCommand = Command.make( · 19 unmodified lines | |||
| 1333 | ); | 1337 | ); |
| 1334 | const execution = yield* client.executions.get({ | 1338 | const execution = yield* client.executions.get({ |
| 1335 | path: { | 1339 | path: { |
| 1336 | workspaceId: installation.workspaceId, | 1340 | workspaceId: installation.scopeId, |
| 1337 | executionId: decodedExecutionId, | 1341 | executionId: decodedExecutionId, |
| 1338 | }, | 1342 | }, |
| 1339 | }); | 1343 | }); |
| 1340 | 1344 | ||
| 1341 | const settled = yield* driveExecution({ | 1345 | const settled = yield* driveExecution({ |
| 1342 | client, | 1346 | client, |
| 1343 | workspaceId: installation.workspaceId, | 1347 | workspaceId: installation.scopeId, |
| 1344 | envelope: execution, | 1348 | envelope: execution, |
| 1345 | baseUrl, | 1349 | baseUrl, |
| 1346 | shouldOpenUrls: !noOpen, | 1350 | shouldOpenUrls: !noOpen, |
| @@ -65,8 +65,8 @@ describe("distribution flow", () => { · 64 unmodified lines | |||
| 65 | const installationResponse = yield* harness.fetchText("/v1/local/installation"); | 65 | const installationResponse = yield* harness.fetchText("/v1/local/installation"); |
| 66 | expect(installationResponse.status).toBe(200); | 66 | expect(installationResponse.status).toBe(200); |
| 67 | const installation = JSON.parse(installationResponse.body) as { | 67 | const installation = JSON.parse(installationResponse.body) as { |
| 68 | workspaceId: string; | 68 | scopeId: string; |
| 69 | accountId: string; | 69 | actorScopeId: string; |
| 70 | }; | 70 | }; |
| 71 | 71 | ||
| 72 | const sesCall = yield* runCommand( | 72 | const sesCall = yield* runCommand( |
| @@ -88,12 +88,12 @@ describe("distribution flow", () => { · 15 unmodified lines | |||
| 88 | const installationAfterRestart = JSON.parse( | 88 | const installationAfterRestart = JSON.parse( |
| 89 | installationAfterRestartResponse.body, | 89 | installationAfterRestartResponse.body, |
| 90 | ) as { | 90 | ) as { |
| 91 | workspaceId: string; | 91 | scopeId: string; |
| 92 | accountId: string; | 92 | actorScopeId: string; |
| 93 | }; | 93 | }; |
| 94 | 94 | ||
| 95 | expect(installationAfterRestart.workspaceId).toBe(installation.workspaceId); | 95 | expect(installationAfterRestart.scopeId).toBe(installation.scopeId); |
| 96 | expect(installationAfterRestart.accountId).toBe(installation.accountId); | 96 | expect(installationAfterRestart.actorScopeId).toBe(installation.actorScopeId); |
| 97 | 97 | ||
| 98 | yield* runCommand(["down", "--base-url", harness.baseUrl]); | 98 | yield* runCommand(["down", "--base-url", harness.baseUrl]); |
| 99 | }); | 99 | }); |
| @@ -39,7 +39,7 @@ const createApiClientHarness = () => · 38 unmodified lines | |||
| 39 | const installation = yield* bootstrapClient.local.installation({}); | 39 | const installation = yield* bootstrapClient.local.installation({}); |
| 40 | const client = yield* createExecutorApiClient({ | 40 | const client = yield* createExecutorApiClient({ |
| 41 | baseUrl: server.baseUrl, | 41 | baseUrl: server.baseUrl, |
| 42 | accountId: installation.accountId, | 42 | accountId: installation.actorScopeId, |
| 43 | }); | 43 | }); |
| 44 | 44 | ||
| 45 | return { | 45 | return { |
| @@ -75,7 +75,7 @@ describe("local-executor-server real ingestion", () => { · 29 unmodified lines | |||
| 75 | 75 | ||
| 76 | const connected = yield* client.sources.connect({ | 76 | const connected = yield* client.sources.connect({ |
| 77 | path: { | 77 | path: { |
| 78 | workspaceId: installation.workspaceId, | 78 | workspaceId: installation.scopeId, |
| 79 | }, | 79 | }, |
| 80 | payload: { | 80 | payload: { |
| 81 | kind: "openapi", | 81 | kind: "openapi", |
| @@ -96,7 +96,7 @@ describe("local-executor-server real ingestion", () => { · 14 unmodified lines | |||
| 96 | 96 | ||
| 97 | const inspection = yield* client.sources.inspection({ | 97 | const inspection = yield* client.sources.inspection({ |
| 98 | path: { | 98 | path: { |
| 99 | workspaceId: installation.workspaceId, | 99 | workspaceId: installation.scopeId, |
| 100 | sourceId: connected.source.id, | 100 | sourceId: connected.source.id, |
| 101 | }, | 101 | }, |
| 102 | }); | 102 | }); |
| @@ -106,7 +106,7 @@ describe("local-executor-server real ingestion", () => { · 3 unmodified lines | |||
| 106 | 106 | ||
| 107 | const discoveredTools = yield* client.sources.inspectionDiscover({ | 107 | const discoveredTools = yield* client.sources.inspectionDiscover({ |
| 108 | path: { | 108 | path: { |
| 109 | workspaceId: installation.workspaceId, | 109 | workspaceId: installation.scopeId, |
| 110 | sourceId: connected.source.id, | 110 | sourceId: connected.source.id, |
| 111 | }, | 111 | }, |
| 112 | payload: { | 112 | payload: { |
| @@ -137,7 +137,7 @@ describe("local-executor-server real ingestion", () => { · 24 unmodified lines | |||
| 137 | 137 | ||
| 138 | const connected = yield* client.sources.connect({ | 138 | const connected = yield* client.sources.connect({ |
| 139 | path: { | 139 | path: { |
| 140 | workspaceId: installation.workspaceId, | 140 | workspaceId: installation.scopeId, |
| 141 | }, | 141 | }, |
| 142 | payload: { | 142 | payload: { |
| 143 | kind: "graphql", | 143 | kind: "graphql", |
| @@ -159,7 +159,7 @@ describe("local-executor-server real ingestion", () => { · 15 unmodified lines | |||
| 159 | 159 | ||
| 160 | const inspection = yield* client.sources.inspection({ | 160 | const inspection = yield* client.sources.inspection({ |
| 161 | path: { | 161 | path: { |
| 162 | workspaceId: installation.workspaceId, | 162 | workspaceId: installation.scopeId, |
| 163 | sourceId: connected.source.id, | 163 | sourceId: connected.source.id, |
| 164 | }, | 164 | }, |
| 165 | }); | 165 | }); |
| @@ -175,7 +175,7 @@ describe("local-executor-server real ingestion", () => { · 9 unmodified lines | |||
| 175 | 175 | ||
| 176 | const toolDetail = yield* client.sources.inspectionTool({ | 176 | const toolDetail = yield* client.sources.inspectionTool({ |
| 177 | path: { | 177 | path: { |
| 178 | workspaceId: installation.workspaceId, | 178 | workspaceId: installation.scopeId, |
| 179 | sourceId: connected.source.id, | 179 | sourceId: connected.source.id, |
| 180 | toolPath: "linear.administrableTeams", | 180 | toolPath: "linear.administrableTeams", |
| 181 | }, | 181 | }, |
| @@ -191,7 +191,7 @@ describe("local-executor-server real ingestion", () => { · 9 unmodified lines | |||
| 191 | 191 | ||
| 192 | const storedSource = yield* client.sources.get({ | 192 | const storedSource = yield* client.sources.get({ |
| 193 | path: { | 193 | path: { |
| 194 | workspaceId: installation.workspaceId, | 194 | workspaceId: installation.scopeId, |
| 195 | sourceId: connected.source.id, | 195 | sourceId: connected.source.id, |
| 196 | }, | 196 | }, |
| 197 | }); | 197 | }); |
| @@ -218,7 +218,7 @@ describe("local-executor-server real ingestion", () => { · 20 unmodified lines | |||
| 218 | 218 | ||
| 219 | const connected = yield* client.sources.connect({ | 219 | const connected = yield* client.sources.connect({ |
| 220 | path: { | 220 | path: { |
| 221 | workspaceId: installation.workspaceId, | 221 | workspaceId: installation.scopeId, |
| 222 | }, | 222 | }, |
| 223 | payload: { | 223 | payload: { |
| 224 | kind: "mcp", | 224 | kind: "mcp", |
| @@ -235,7 +235,7 @@ describe("local-executor-server real ingestion", () => { · 10 unmodified lines | |||
| 235 | 235 | ||
| 236 | const inspection = yield* client.sources.inspection({ | 236 | const inspection = yield* client.sources.inspection({ |
| 237 | path: { | 237 | path: { |
| 238 | workspaceId: installation.workspaceId, | 238 | workspaceId: installation.scopeId, |
| 239 | sourceId: connected.source.id, | 239 | sourceId: connected.source.id, |
| 240 | }, | 240 | }, |
| 241 | }); | 241 | }); |
| @@ -245,7 +245,7 @@ describe("local-executor-server real ingestion", () => { · 3 unmodified lines | |||
| 245 | 245 | ||
| 246 | const discoveredTools = yield* client.sources.inspectionDiscover({ | 246 | const discoveredTools = yield* client.sources.inspectionDiscover({ |
| 247 | path: { | 247 | path: { |
| 248 | workspaceId: installation.workspaceId, | 248 | workspaceId: installation.scopeId, |
| 249 | sourceId: connected.source.id, | 249 | sourceId: connected.source.id, |
| 250 | }, | 250 | }, |
| 251 | payload: { | 251 | payload: { |
| @@ -1,4 +1,4 @@ | |||
| 1 | import { createServer, type IncomingMessage, type ServerResponse } from "node:http"; | 1 | import { type IncomingMessage, type ServerResponse } from "node:http"; |
| 2 | import { randomUUID } from "node:crypto"; | 2 | import { randomUUID } from "node:crypto"; |
| 3 | 3 | ||
| 4 | import { | 4 | import { |
| @@ -6,17 +6,19 @@ import { · 1 unmodified line | |||
| 6 | HttpApiEndpoint, | 6 | HttpApiEndpoint, |
| 7 | HttpApiGroup, | 7 | HttpApiGroup, |
| 8 | HttpApiSchema, | 8 | HttpApiSchema, |
| 9 | OpenApi, | 9 | HttpApiBuilder, |
| 10 | FileSystem, | 10 | FileSystem, |
| 11 | } from "@effect/platform"; | 11 | } from "@effect/platform"; |
| 12 | import { NodeFileSystem } from "@effect/platform-node"; | 12 | import { NodeFileSystem } from "@effect/platform-node"; |
| 13 | import { describe, expect, it } from "@effect/vitest"; | 13 | import { describe, expect, it } from "@effect/vitest"; |
| 14 | import { assertTrue } from "@effect/vitest/utils"; | 14 | import { assertTrue } from "@effect/vitest/utils"; |
| 15 | import * as Effect from "effect/Effect"; | 15 | import * as Effect from "effect/Effect"; |
| 16 | import * as Layer from "effect/Layer"; | ||
| 16 | import * as Schema from "effect/Schema"; | 17 | import * as Schema from "effect/Schema"; |
| 17 | 18 | ||
| 18 | import { startMcpElicitationDemoServer } from "@executor/mcp-elicitation-demo"; | 19 | import { startMcpElicitationDemoServer } from "@executor/mcp-elicitation-demo"; |
| 19 | import { makeToolInvokerFromTools, toTool } from "@executor/codemode-core"; | 20 | import { makeToolInvokerFromTools, toTool } from "@executor/codemode-core"; |
| 21 | import { startOpenApiTestServer } from "@executor/effect-test-utils"; | ||
| 20 | import { | 22 | import { |
| 21 | createExecutorApiClient, | 23 | createExecutorApiClient, |
| 22 | executorOpenApiSpec, | 24 | executorOpenApiSpec, |
| @@ -122,7 +124,7 @@ const writeConfiguredLocalMcpSource = (input: { · 99 unmodified lines | |||
| 122 | 124 | ||
| 123 | const source = { | 125 | const source = { |
| 124 | id: sourceId, | 126 | id: sourceId, |
| 125 | workspaceId: installation.workspaceId, | 127 | scopeId: installation.scopeId, |
| 126 | name: input.name ?? "Demo", | 128 | name: input.name ?? "Demo", |
| 127 | kind: "mcp" as const, | 129 | kind: "mcp" as const, |
| 128 | endpoint: input.endpoint, | 130 | endpoint: input.endpoint, |
| @@ -196,7 +198,7 @@ const createApiClientHarness = () => · 67 unmodified lines | |||
| 196 | const installation = yield* bootstrapClient.local.installation({}); | 198 | const installation = yield* bootstrapClient.local.installation({}); |
| 197 | const client = yield* createExecutorApiClient({ | 199 | const client = yield* createExecutorApiClient({ |
| 198 | baseUrl: server.baseUrl, | 200 | baseUrl: server.baseUrl, |
| 199 | accountId: installation.accountId, | 201 | accountId: installation.actorScopeId, |
| 200 | }); | 202 | }); |
| 201 | 203 | ||
| 202 | return { | 204 | return { |
| @@ -288,161 +290,89 @@ const repoParam = HttpApiSchema.param("repo", Schema.String); · 85 unmodified lines | |||
| 288 | class ExecutorDemoReposApi extends HttpApiGroup.make("repos") | 290 | class ExecutorDemoReposApi extends HttpApiGroup.make("repos") |
| 289 | .add( | 291 | .add( |
| 290 | HttpApiEndpoint.get("getRepo")`/repos/${ownerParam}/${repoParam}` | 292 | HttpApiEndpoint.get("getRepo")`/repos/${ownerParam}/${repoParam}` |
| 291 | .addSuccess( | 293 | .addSuccess(Schema.Unknown), |
| 292 | Schema.Struct({ | ||
| 293 | full_name: Schema.String, | ||
| 294 | private: Schema.Boolean, | ||
| 295 | }), | ||
| 296 | ), | ||
| 297 | ) | 294 | ) |
| 298 | {} | 295 | {} |
| 299 | 296 | ||
| 300 | class ExecutorDemoApi extends HttpApi.make("executorDemo").add(ExecutorDemoReposApi) {} | 297 | class ExecutorDemoApi extends HttpApi.make("executorDemo").add(ExecutorDemoReposApi) {} |
| 301 | 298 | ||
| 302 | const executorDemoOpenApiSpec = OpenApi.fromApi(ExecutorDemoApi); | 299 | class ExecutorDnsRecordsApi extends HttpApiGroup.make("records") |
| 300 | .add( | ||
| 301 | HttpApiEndpoint.post("createRecord")`/records` | ||
| 302 | .setPayload( | ||
| 303 | Schema.Struct({ | ||
| 304 | type: Schema.optional(Schema.String), | ||
| 305 | name: Schema.optional(Schema.String), | ||
| 306 | value: Schema.String, | ||
| 307 | }), | ||
| 308 | ) | ||
| 309 | .addSuccess(Schema.Unknown), | ||
| 310 | ) | ||
| 311 | {} | ||
| 312 | |||
| 313 | class ExecutorDnsApi extends HttpApi.make("executorDns").add( | ||
| 314 | ExecutorDnsRecordsApi, | ||
| 315 | ) {} | ||
| 303 | 316 | ||
| 304 | const startOpenApiDemoServer = async () => { | 317 | const startOpenApiDemoServer = async () => { |
| 305 | const seenAuthHeaders: Array<string | null> = []; | 318 | const seenAuthHeaders: Array<string | null> = []; |
| 319 | const executorDemoLive = HttpApiBuilder.group( | ||
| 320 | ExecutorDemoApi, | ||
| 321 | "repos", | ||
| 322 | (handlers) => | ||
| 323 | handlers.handle("getRepo", ({ path, request }) => { | ||
| 324 | const authorization = request.headers.authorization; | ||
| 325 | if (typeof authorization === "string") { | ||
| 326 | seenAuthHeaders.push(authorization); | ||
| 327 | } else { | ||
| 328 | seenAuthHeaders.push(null); | ||
| 329 | } | ||
| 306 | 330 | ||
| 307 | const handler = (req: IncomingMessage, res: ServerResponse) => { | 331 | return Effect.succeed({ |
| 308 | if (req.url === "/openapi.json") { | 332 | full_name: `${path.owner}/${path.repo}`, |
| 309 | res.statusCode = 200; | ||
| 310 | res.setHeader("content-type", "application/json"); | ||
| 311 | res.end(JSON.stringify(executorDemoOpenApiSpec)); | ||
| 312 | return; | ||
| 313 | } | ||
| 314 | |||
| 315 | const match = req.url?.match(/^\/repos\/([^/]+)\/([^/]+)$/); | ||
| 316 | if (req.method === "GET" && match) { | ||
| 317 | seenAuthHeaders.push( | ||
| 318 | typeof req.headers.authorization === "string" ? req.headers.authorization : null, | ||
| 319 | ); | ||
| 320 | res.statusCode = 200; | ||
| 321 | res.setHeader("content-type", "application/json"); | ||
| 322 | res.end( | ||
| 323 | JSON.stringify({ | ||
| 324 | full_name: `${decodeURIComponent(match[1] ?? "")}/${decodeURIComponent(match[2] ?? "")}`, | ||
| 325 | private: false, | 333 | private: false, |
| 326 | }), | 334 | }); |
| 327 | ); | 335 | }), |
| 328 | return; | 336 | ); |
| 329 | } | ||
| 330 | |||
| 331 | res.statusCode = 404; | ||
| 332 | res.end("not found"); | ||
| 333 | }; | ||
| 334 | 337 | ||
| 335 | const server = createServer(handler); | 338 | const server = await startOpenApiTestServer({ |
| 336 | await new Promise<void>((resolve, reject) => { | 339 | apiLayer: HttpApiBuilder.api(ExecutorDemoApi).pipe( |
| 337 | server.once("error", reject); | 340 | Layer.provide(executorDemoLive), |
| 338 | server.listen(0, "127.0.0.1", () => resolve()); | 341 | ), |
| 339 | }); | 342 | }); |
| 340 | const address = server.address(); | ||
| 341 | if (!address || typeof address === "string") { | ||
| 342 | throw new Error("Failed to bind OpenAPI demo server"); | ||
| 343 | } | ||
| 344 | 343 | ||
| 345 | return { | 344 | return { |
| 346 | baseUrl: `http://127.0.0.1:${address.port}`, | 345 | ...server, |
| 347 | specUrl: `http://127.0.0.1:${address.port}/openapi.json`, | ||
| 348 | seenAuthHeaders, | 346 | seenAuthHeaders, |
| 349 | close: () => | ||
| 350 | new Promise<void>((resolve, reject) => { | ||
| 351 | server.close((error) => (error ? reject(error) : resolve())); | ||
| 352 | }), | ||
| 353 | }; | 347 | }; |
| 354 | }; | 348 | }; |
| 355 | 349 | ||
| 356 | const startMutatingOpenApiDemoServer = async () => { | 350 | const startMutatingOpenApiDemoServer = async () => { |
| 357 | const createdBodies: Array<Record<string, unknown>> = []; | 351 | const createdBodies: Array<Record<string, unknown>> = []; |
| 358 | const openApiDocument = JSON.stringify({ | 352 | const executorDnsLive = HttpApiBuilder.group( |
| 359 | openapi: "3.0.3", | 353 | ExecutorDnsApi, |
| 360 | info: { | 354 | "records", |
| 361 | title: "Executor DNS Demo API", | 355 | (handlers) => |
| 362 | version: "1.0.0", | 356 | handlers.handle("createRecord", ({ payload }) => { |
| 363 | }, | 357 | createdBodies.push(payload); |
| 364 | paths: { | 358 | |
| 365 | "/records": { | 359 | return Effect.succeed({ |
| 366 | post: { | ||
| 367 | operationId: "records.createRecord", | ||
| 368 | tags: ["records"], | ||
| 369 | summary: "Create a DNS record", | ||
| 370 | requestBody: { | ||
| 371 | required: true, | ||
| 372 | content: { | ||
| 373 | "application/json": { | ||
| 374 | schema: { | ||
| 375 | type: "object", | ||
| 376 | properties: { | ||
| 377 | type: { type: "string" }, | ||
| 378 | name: { type: "string" }, | ||
| 379 | value: { type: "string" }, | ||
| 380 | }, | ||
| 381 | required: ["type", "value"], | ||
| 382 | }, | ||
| 383 | }, | ||
| 384 | }, | ||
| 385 | }, | ||
| 386 | responses: { | ||
| 387 | 200: { | ||
| 388 | description: "ok", | ||
| 389 | }, | ||
| 390 | }, | ||
| 391 | }, | ||
| 392 | }, | ||
| 393 | }, | ||
| 394 | }); | ||
| 395 | |||
| 396 | const handler = (req: IncomingMessage, res: ServerResponse) => { | ||
| 397 | if (req.url === "/openapi.json") { | ||
| 398 | res.statusCode = 200; | ||
| 399 | res.setHeader("content-type", "application/json"); | ||
| 400 | res.end(openApiDocument); | ||
| 401 | return; | ||
| 402 | } | ||
| 403 | |||
| 404 | if (req.method === "POST" && req.url === "/records") { | ||
| 405 | const chunks: Array<Buffer> = []; | ||
| 406 | req.on("data", (chunk) => { | ||
| 407 | chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk)); | ||
| 408 | }); | ||
| 409 | req.on("end", () => { | ||
| 410 | const raw = Buffer.concat(chunks).toString("utf8"); | ||
| 411 | const parsed = JSON.parse(raw) as Record<string, unknown>; | ||
| 412 | createdBodies.push(parsed); | ||
| 413 | res.statusCode = 200; | ||
| 414 | res.setHeader("content-type", "application/json"); | ||
| 415 | res.end(JSON.stringify({ | ||
| 416 | ok: true, | 360 | ok: true, |
| 417 | id: `rec_${createdBodies.length}`, | 361 | id: `rec_${createdBodies.length}`, |
| 418 | record: parsed, | 362 | record: payload, |
| 419 | })); | 363 | }); |
| 420 | }); | 364 | }), |
| 421 | return; | 365 | ); |
| 422 | } | ||
| 423 | |||
| 424 | res.statusCode = 404; | ||
| 425 | res.end("not found"); | ||
| 426 | }; | ||
| 427 | 366 | ||
| 428 | const server = createServer(handler); | 367 | const server = await startOpenApiTestServer({ |
| 429 | await new Promise<void>((resolve, reject) => { | 368 | apiLayer: HttpApiBuilder.api(ExecutorDnsApi).pipe( |
| 430 | server.once("error", reject); | 369 | Layer.provide(executorDnsLive), |
| 431 | server.listen(0, "127.0.0.1", () => resolve()); | 370 | ), |
| 432 | }); | 371 | }); |
| 433 | const address = server.address(); | ||
| 434 | if (!address || typeof address === "string") { | ||
| 435 | throw new Error("Failed to bind mutating OpenAPI demo server"); | ||
| 436 | } | ||
| 437 | 372 | ||
| 438 | return { | 373 | return { |
| 439 | baseUrl: `http://127.0.0.1:${address.port}`, | 374 | ...server, |
| 440 | specUrl: `http://127.0.0.1:${address.port}/openapi.json`, | ||
| 441 | createdBodies, | 375 | createdBodies, |
| 442 | close: () => | ||
| 443 | new Promise<void>((resolve, reject) => { | ||
| 444 | server.close((error) => (error ? reject(error) : resolve())); | ||
| 445 | }), | ||
| 446 | }; | 376 | }; |
| 447 | }; | 377 | }; |
| 448 | 378 | ||
| @@ -750,12 +680,12 @@ describe("local-executor-server", () => { · 301 unmodified lines | |||
| 750 | const installation = yield* bootstrapClient.local.installation({}); | 680 | const installation = yield* bootstrapClient.local.installation({}); |
| 751 | const client = yield* createExecutorApiClient({ | 681 | const client = yield* createExecutorApiClient({ |
| 752 | baseUrl: server.baseUrl, | 682 | baseUrl: server.baseUrl, |
| 753 | accountId: installation.accountId, | 683 | accountId: installation.actorScopeId, |
| 754 | }); | 684 | }); |
| 755 | 685 | ||
| 756 | const execution = yield* client.executions.create({ | 686 | const execution = yield* client.executions.create({ |
| 757 | path: { | 687 | path: { |
| 758 | workspaceId: installation.workspaceId, | 688 | workspaceId: installation.scopeId, |
| 759 | }, | 689 | }, |
| 760 | payload: { | 690 | payload: { |
| 761 | code: "return await tools.math.add({ a: 20, b: 22 });", | 691 | code: "return await tools.math.add({ a: 20, b: 22 });", |
| @@ -951,12 +881,12 @@ describe("local-executor-server", () => { · 189 unmodified lines | |||
| 951 | const installation = yield* bootstrapClient.local.installation({}); | 881 | const installation = yield* bootstrapClient.local.installation({}); |
| 952 | const client = yield* createExecutorApiClient({ | 882 | const client = yield* createExecutorApiClient({ |
| 953 | baseUrl: server.baseUrl, | 883 | baseUrl: server.baseUrl, |
| 954 | accountId: installation.accountId, | 884 | accountId: installation.actorScopeId, |
| 955 | }); | 885 | }); |
| 956 | 886 | ||
| 957 | yield* client.sources.create({ | 887 | yield* client.sources.create({ |
| 958 | path: { | 888 | path: { |
| 959 | workspaceId: installation.workspaceId, | 889 | workspaceId: installation.scopeId, |
| 960 | }, | 890 | }, |
| 961 | payload: { | 891 | payload: { |
| 962 | name: "Demo", | 892 | name: "Demo", |
| @@ -978,7 +908,7 @@ describe("local-executor-server", () => { · 15 unmodified lines | |||
| 978 | 908 | ||
| 979 | const created = yield* client.executions.create({ | 909 | const created = yield* client.executions.create({ |
| 980 | path: { | 910 | path: { |
| 981 | workspaceId: installation.workspaceId, | 911 | workspaceId: installation.scopeId, |
| 982 | }, | 912 | }, |
| 983 | payload: { | 913 | payload: { |
| 984 | code: 'return await tools.demo.gated_echo({ value: "from-daemon" });', | 914 | code: 'return await tools.demo.gated_echo({ value: "from-daemon" });', |
| @@ -995,7 +925,7 @@ describe("local-executor-server", () => { · 10 unmodified lines | |||
| 995 | 925 | ||
| 996 | const approved = yield* client.executions.resume({ | 926 | const approved = yield* client.executions.resume({ |
| 997 | path: { | 927 | path: { |
| 998 | workspaceId: installation.workspaceId, | 928 | workspaceId: installation.scopeId, |
| 999 | executionId: created.execution.id, | 929 | executionId: created.execution.id, |
| 1000 | }, | 930 | }, |
| 1001 | payload: { | 931 | payload: { |
| @@ -1018,7 +948,7 @@ describe("local-executor-server", () => { · 16 unmodified lines | |||
| 1018 | 948 | ||
| 1019 | const resumed = yield* client.executions.resume({ | 949 | const resumed = yield* client.executions.resume({ |
| 1020 | path: { | 950 | path: { |
| 1021 | workspaceId: installation.workspaceId, | 951 | workspaceId: installation.scopeId, |
| 1022 | executionId: created.execution.id, | 952 | executionId: created.execution.id, |
| 1023 | }, | 953 | }, |
| 1024 | payload: { | 954 | payload: { |
| @@ -1057,12 +987,12 @@ describe("local-executor-server", () => { · 32 unmodified lines | |||
| 1057 | const installation = yield* bootstrapClient.local.installation({}); | 987 | const installation = yield* bootstrapClient.local.installation({}); |
| 1058 | const client = yield* createExecutorApiClient({ | 988 | const client = yield* createExecutorApiClient({ |
| 1059 | baseUrl: server.baseUrl, | 989 | baseUrl: server.baseUrl, |
| 1060 | accountId: installation.accountId, | 990 | accountId: installation.actorScopeId, |
| 1061 | }); | 991 | }); |
| 1062 | 992 | ||
| 1063 | yield* client.sources.create({ | 993 | yield* client.sources.create({ |
| 1064 | path: { | 994 | path: { |
| 1065 | workspaceId: installation.workspaceId, | 995 | workspaceId: installation.scopeId, |
| 1066 | }, | 996 | }, |
| 1067 | payload: { | 997 | payload: { |
| 1068 | name: "Demo", | 998 | name: "Demo", |
| @@ -1085,7 +1015,7 @@ describe("local-executor-server", () => { · 16 unmodified lines | |||
| 1085 | for (const value of ["first", "second"]) { | 1015 | for (const value of ["first", "second"]) { |
| 1086 | const created = yield* client.executions.create({ | 1016 | const created = yield* client.executions.create({ |
| 1087 | path: { | 1017 | path: { |
| 1088 | workspaceId: installation.workspaceId, | 1018 | workspaceId: installation.scopeId, |
| 1089 | }, | 1019 | }, |
| 1090 | payload: { | 1020 | payload: { |
| 1091 | code: `return await tools.demo.gated_echo({ value: "${value}" });`, | 1021 | code: `return await tools.demo.gated_echo({ value: "${value}" });`, |
| @@ -1098,7 +1028,7 @@ describe("local-executor-server", () => { · 6 unmodified lines | |||
| 1098 | 1028 | ||
| 1099 | const approved = yield* client.executions.resume({ | 1029 | const approved = yield* client.executions.resume({ |
| 1100 | path: { | 1030 | path: { |
| 1101 | workspaceId: installation.workspaceId, | 1031 | workspaceId: installation.scopeId, |
| 1102 | executionId: created.execution.id, | 1032 | executionId: created.execution.id, |
| 1103 | }, | 1033 | }, |
| 1104 | payload: { | 1034 | payload: { |
| @@ -1121,7 +1051,7 @@ describe("local-executor-server", () => { · 16 unmodified lines | |||
| 1121 | 1051 | ||
| 1122 | const resumed = yield* client.executions.resume({ | 1052 | const resumed = yield* client.executions.resume({ |
| 1123 | path: { | 1053 | path: { |
| 1124 | workspaceId: installation.workspaceId, | 1054 | workspaceId: installation.scopeId, |
| 1125 | executionId: created.execution.id, | 1055 | executionId: created.execution.id, |
| 1126 | }, | 1056 | }, |
| 1127 | payload: { | 1057 | payload: { |
| @@ -1160,12 +1090,12 @@ describe("local-executor-server", () => { · 32 unmodified lines | |||
| 1160 | const installation = yield* bootstrapClient.local.installation({}); | 1090 | const installation = yield* bootstrapClient.local.installation({}); |
| 1161 | const client = yield* createExecutorApiClient({ | 1091 | const client = yield* createExecutorApiClient({ |
| 1162 | baseUrl: server.baseUrl, | 1092 | baseUrl: server.baseUrl, |
| 1163 | accountId: installation.accountId, | 1093 | accountId: installation.actorScopeId, |
| 1164 | }); | 1094 | }); |
| 1165 | 1095 | ||
| 1166 | const existing = yield* client.sources.create({ | 1096 | const existing = yield* client.sources.create({ |
| 1167 | path: { | 1097 | path: { |
| 1168 | workspaceId: installation.workspaceId, | 1098 | workspaceId: installation.scopeId, |
| 1169 | }, | 1099 | }, |
| 1170 | payload: { | 1100 | payload: { |
| 1171 | name: "Demo", | 1101 | name: "Demo", |
| @@ -1187,7 +1117,7 @@ describe("local-executor-server", () => { · 15 unmodified lines | |||
| 1187 | 1117 | ||
| 1188 | const seeded = yield* seedDemoMcpSourceInWorkspace({ | 1118 | const seeded = yield* seedDemoMcpSourceInWorkspace({ |
| 1189 | client, | 1119 | client, |
| 1190 | workspaceId: installation.workspaceId, | 1120 | workspaceId: installation.scopeId, |
| 1191 | endpoint: demoServer.endpoint, | 1121 | endpoint: demoServer.endpoint, |
| 1192 | name: "Demo", | 1122 | name: "Demo", |
| 1193 | namespace: "demo", | 1123 | namespace: "demo", |
| @@ -1198,7 +1128,7 @@ describe("local-executor-server", () => { · 4 unmodified lines | |||
| 1198 | 1128 | ||
| 1199 | const sources = yield* client.sources.list({ | 1129 | const sources = yield* client.sources.list({ |
| 1200 | path: { | 1130 | path: { |
| 1201 | workspaceId: installation.workspaceId, | 1131 | workspaceId: installation.scopeId, |
| 1202 | }, | 1132 | }, |
| 1203 | }); | 1133 | }); |
| 1204 | 1134 | ||
| @@ -1249,12 +1179,12 @@ describe("local-executor-server", () => { · 44 unmodified lines | |||
| 1249 | const installation = yield* bootstrapClient.local.installation({}); | 1179 | const installation = yield* bootstrapClient.local.installation({}); |
| 1250 | const client = yield* createExecutorApiClient({ | 1180 | const client = yield* createExecutorApiClient({ |
| 1251 | baseUrl: server.baseUrl, | 1181 | baseUrl: server.baseUrl, |
| 1252 | accountId: installation.accountId, | 1182 | accountId: installation.actorScopeId, |
| 1253 | }); | 1183 | }); |
| 1254 | 1184 | ||
| 1255 | yield* seedGithubOpenApiSourceInWorkspace({ | 1185 | yield* seedGithubOpenApiSourceInWorkspace({ |
| 1256 | client, | 1186 | client, |
| 1257 | workspaceId: installation.workspaceId, | 1187 | workspaceId: installation.scopeId, |
| 1258 | endpoint: openApiServer.baseUrl, | 1188 | endpoint: openApiServer.baseUrl, |
| 1259 | specUrl: openApiServer.specUrl, | 1189 | specUrl: openApiServer.specUrl, |
| 1260 | name: "GitHub", | 1190 | name: "GitHub", |
| @@ -1263,7 +1193,7 @@ describe("local-executor-server", () => { · 2 unmodified lines | |||
| 1263 | 1193 | ||
| 1264 | const execution = yield* client.executions.create({ | 1194 | const execution = yield* client.executions.create({ |
| 1265 | path: { | 1195 | path: { |
| 1266 | workspaceId: installation.workspaceId, | 1196 | workspaceId: installation.scopeId, |
| 1267 | }, | 1197 | }, |
| 1268 | payload: { | 1198 | payload: { |
| 1269 | code: 'return await tools.github.repos.getRepo({ owner: "vercel", repo: "ai" });', | 1199 | code: 'return await tools.github.repos.getRepo({ owner: "vercel", repo: "ai" });', |
| @@ -1287,7 +1217,7 @@ describe("local-executor-server", () => { · 17 unmodified lines | |||
| 1287 | 1217 | ||
| 1288 | const connected = yield* client.sources.connect({ | 1218 | const connected = yield* client.sources.connect({ |
| 1289 | path: { | 1219 | path: { |
| 1290 | workspaceId: installation.workspaceId, | 1220 | workspaceId: installation.scopeId, |
| 1291 | }, | 1221 | }, |
| 1292 | payload: { | 1222 | payload: { |
| 1293 | kind: "openapi", | 1223 | kind: "openapi", |
| @@ -1309,7 +1239,7 @@ describe("local-executor-server", () => { · 15 unmodified lines | |||
| 1309 | 1239 | ||
| 1310 | const sources = yield* client.sources.list({ | 1240 | const sources = yield* client.sources.list({ |
| 1311 | path: { | 1241 | path: { |
| 1312 | workspaceId: installation.workspaceId, | 1242 | workspaceId: installation.scopeId, |
| 1313 | }, | 1243 | }, |
| 1314 | }); | 1244 | }); |
| 1315 | 1245 | ||
| @@ -1318,7 +1248,7 @@ describe("local-executor-server", () => { · 2 unmodified lines | |||
| 1318 | 1248 | ||
| 1319 | const execution = yield* client.executions.create({ | 1249 | const execution = yield* client.executions.create({ |
| 1320 | path: { | 1250 | path: { |
| 1321 | workspaceId: installation.workspaceId, | 1251 | workspaceId: installation.scopeId, |
| 1322 | }, | 1252 | }, |
| 1323 | payload: { | 1253 | payload: { |
| 1324 | code: 'return await tools.github.repos.getRepo({ owner: "vercel", repo: "ai" });', | 1254 | code: 'return await tools.github.repos.getRepo({ owner: "vercel", repo: "ai" });', |
| @@ -1343,7 +1273,7 @@ describe("local-executor-server", () => { · 18 unmodified lines | |||
| 1343 | 1273 | ||
| 1344 | const connected = yield* client.sources.connect({ | 1274 | const connected = yield* client.sources.connect({ |
| 1345 | path: { | 1275 | path: { |
| 1346 | workspaceId: installation.workspaceId, | 1276 | workspaceId: installation.scopeId, |
| 1347 | }, | 1277 | }, |
| 1348 | payload: { | 1278 | payload: { |
| 1349 | kind: "mcp", | 1279 | kind: "mcp", |
| @@ -1361,7 +1291,7 @@ describe("local-executor-server", () => { · 11 unmodified lines | |||
| 1361 | 1291 | ||
| 1362 | const execution = yield* client.executions.create({ | 1292 | const execution = yield* client.executions.create({ |
| 1363 | path: { | 1293 | path: { |
| 1364 | workspaceId: installation.workspaceId, | 1294 | workspaceId: installation.scopeId, |
| 1365 | }, | 1295 | }, |
| 1366 | payload: { | 1296 | payload: { |
| 1367 | code: 'return await tools.demo.gated_echo({ value: "from-api-client" });', | 1297 | code: 'return await tools.demo.gated_echo({ value: "from-api-client" });', |
| @@ -1379,7 +1309,7 @@ describe("local-executor-server", () => { · 11 unmodified lines | |||
| 1379 | 1309 | ||
| 1380 | const approved = yield* client.executions.resume({ | 1310 | const approved = yield* client.executions.resume({ |
| 1381 | path: { | 1311 | path: { |
| 1382 | workspaceId: installation.workspaceId, | 1312 | workspaceId: installation.scopeId, |
| 1383 | executionId: execution.execution.id, | 1313 | executionId: execution.execution.id, |
| 1384 | }, | 1314 | }, |
| 1385 | payload: { | 1315 | payload: { |
| @@ -1405,7 +1335,7 @@ describe("local-executor-server", () => { · 19 unmodified lines | |||
| 1405 | 1335 | ||
| 1406 | const resumed = yield* client.executions.resume({ | 1336 | const resumed = yield* client.executions.resume({ |
| 1407 | path: { | 1337 | path: { |
| 1408 | workspaceId: installation.workspaceId, | 1338 | workspaceId: installation.scopeId, |
| 1409 | executionId: execution.execution.id, | 1339 | executionId: execution.execution.id, |
| 1410 | }, | 1340 | }, |
| 1411 | payload: { | 1341 | payload: { |
| @@ -1436,7 +1366,7 @@ describe("local-executor-server", () => { · 24 unmodified lines | |||
| 1436 | 1366 | ||
| 1437 | const connected = yield* client.sources.connect({ | 1367 | const connected = yield* client.sources.connect({ |
| 1438 | path: { | 1368 | path: { |
| 1439 | workspaceId: installation.workspaceId, | 1369 | workspaceId: installation.scopeId, |
| 1440 | }, | 1370 | }, |
| 1441 | payload: { | 1371 | payload: { |
| 1442 | kind: "mcp", | 1372 | kind: "mcp", |
| @@ -1463,7 +1393,7 @@ describe("local-executor-server", () => { · 20 unmodified lines | |||
| 1463 | 1393 | ||
| 1464 | const refreshedSource = yield* client.sources.get({ | 1394 | const refreshedSource = yield* client.sources.get({ |
| 1465 | path: { | 1395 | path: { |
| 1466 | workspaceId: installation.workspaceId, | 1396 | workspaceId: installation.scopeId, |
| 1467 | sourceId: connected.source.id, | 1397 | sourceId: connected.source.id, |
| 1468 | }, | 1398 | }, |
| 1469 | }); | 1399 | }); |
| @@ -1474,7 +1404,7 @@ describe("local-executor-server", () => { · 4 unmodified lines | |||
| 1474 | 1404 | ||
| 1475 | const toolCall = yield* client.executions.create({ | 1405 | const toolCall = yield* client.executions.create({ |
| 1476 | path: { | 1406 | path: { |
| 1477 | workspaceId: installation.workspaceId, | 1407 | workspaceId: installation.scopeId, |
| 1478 | }, | 1408 | }, |
| 1479 | payload: { | 1409 | payload: { |
| 1480 | code: "return await tools.axiom.whoami({});", | 1410 | code: "return await tools.axiom.whoami({});", |
| @@ -1491,7 +1421,7 @@ describe("local-executor-server", () => { · 10 unmodified lines | |||
| 1491 | 1421 | ||
| 1492 | const approvedToolCall = yield* client.executions.resume({ | 1422 | const approvedToolCall = yield* client.executions.resume({ |
| 1493 | path: { | 1423 | path: { |
| 1494 | workspaceId: installation.workspaceId, | 1424 | workspaceId: installation.scopeId, |
| 1495 | executionId: toolCall.execution.id, | 1425 | executionId: toolCall.execution.id, |
| 1496 | }, | 1426 | }, |
| 1497 | payload: { | 1427 | payload: { |
| @@ -1529,12 +1459,12 @@ describe("local-executor-server", () => { · 31 unmodified lines | |||
| 1529 | const installation = yield* bootstrapClient.local.installation({}); | 1459 | const installation = yield* bootstrapClient.local.installation({}); |
| 1530 | const client = yield* createExecutorApiClient({ | 1460 | const client = yield* createExecutorApiClient({ |
| 1531 | baseUrl: server.baseUrl, | 1461 | baseUrl: server.baseUrl, |
| 1532 | accountId: installation.accountId, | 1462 | accountId: installation.actorScopeId, |
| 1533 | }); | 1463 | }); |
| 1534 | 1464 | ||
| 1535 | const added = yield* client.executions.create({ | 1465 | const added = yield* client.executions.create({ |
| 1536 | path: { | 1466 | path: { |
| 1537 | workspaceId: installation.workspaceId, | 1467 | workspaceId: installation.scopeId, |
| 1538 | }, | 1468 | }, |
| 1539 | payload: { | 1469 | payload: { |
| 1540 | code: `return await tools.executor.sources.add({ endpoint: ${JSON.stringify(oauthServer.endpoint)}, name: "Axiom", namespace: "axiom" });`, | 1470 | code: `return await tools.executor.sources.add({ endpoint: ${JSON.stringify(oauthServer.endpoint)}, name: "Axiom", namespace: "axiom" });`, |
| @@ -1563,7 +1493,7 @@ describe("local-executor-server", () => { · 22 unmodified lines | |||
| 1563 | while (true) { | 1493 | while (true) { |
| 1564 | const sources = yield* client.sources.list({ | 1494 | const sources = yield* client.sources.list({ |
| 1565 | path: { | 1495 | path: { |
| 1566 | workspaceId: installation.workspaceId, | 1496 | workspaceId: installation.scopeId, |
| 1567 | }, | 1497 | }, |
| 1568 | }); | 1498 | }); |
| 1569 | const source = sources.find((entry) => entry.namespace === "axiom"); | 1499 | const source = sources.find((entry) => entry.namespace === "axiom"); |
| @@ -1581,7 +1511,7 @@ describe("local-executor-server", () => { · 11 unmodified lines | |||
| 1581 | 1511 | ||
| 1582 | const toolCall = yield* client.executions.create({ | 1512 | const toolCall = yield* client.executions.create({ |
| 1583 | path: { | 1513 | path: { |
| 1584 | workspaceId: installation.workspaceId, | 1514 | workspaceId: installation.scopeId, |
| 1585 | }, | 1515 | }, |
| 1586 | payload: { | 1516 | payload: { |
| 1587 | code: "return await tools.axiom.whoami({});", | 1517 | code: "return await tools.axiom.whoami({});", |
| @@ -1597,7 +1527,7 @@ describe("local-executor-server", () => { · 9 unmodified lines | |||
| 1597 | 1527 | ||
| 1598 | const approvedToolCall = yield* client.executions.resume({ | 1528 | const approvedToolCall = yield* client.executions.resume({ |
| 1599 | path: { | 1529 | path: { |
| 1600 | workspaceId: installation.workspaceId, | 1530 | workspaceId: installation.scopeId, |
| 1601 | executionId: toolCall.execution.id, | 1531 | executionId: toolCall.execution.id, |
| 1602 | }, | 1532 | }, |
| 1603 | payload: { | 1533 | payload: { |
| @@ -1633,12 +1563,12 @@ describe("local-executor-server", () => { · 29 unmodified lines | |||
| 1633 | const installation = yield* bootstrapClient.local.installation({}); | 1563 | const installation = yield* bootstrapClient.local.installation({}); |
| 1634 | const client = yield* createExecutorApiClient({ | 1564 | const client = yield* createExecutorApiClient({ |
| 1635 | baseUrl: server.baseUrl, | 1565 | baseUrl: server.baseUrl, |
| 1636 | accountId: installation.accountId, | 1566 | accountId: installation.actorScopeId, |
| 1637 | }); | 1567 | }); |
| 1638 | 1568 | ||
| 1639 | const connected = yield* client.sources.connect({ | 1569 | const connected = yield* client.sources.connect({ |
| 1640 | path: { | 1570 | path: { |
| 1641 | workspaceId: installation.workspaceId, | 1571 | workspaceId: installation.scopeId, |
| 1642 | }, | 1572 | }, |
| 1643 | payload: { | 1573 | payload: { |
| 1644 | kind: "openapi", | 1574 | kind: "openapi", |
| @@ -1655,7 +1585,7 @@ describe("local-executor-server", () => { · 10 unmodified lines | |||
| 1655 | 1585 | ||
| 1656 | const gated = yield* client.executions.create({ | 1586 | const gated = yield* client.executions.create({ |
| 1657 | path: { | 1587 | path: { |
| 1658 | workspaceId: installation.workspaceId, | 1588 | workspaceId: installation.scopeId, |
| 1659 | }, | 1589 | }, |
| 1660 | payload: { | 1590 | payload: { |
| 1661 | code: 'return await tools.dns.records.createRecord({ body: { type: "TXT", name: "", value: "hello world" } });', | 1591 | code: 'return await tools.dns.records.createRecord({ body: { type: "TXT", name: "", value: "hello world" } });', |
| @@ -1668,12 +1598,12 @@ describe("local-executor-server", () => { · 6 unmodified lines | |||
| 1668 | throw new Error("Expected pending approval interaction"); | 1598 | throw new Error("Expected pending approval interaction"); |
| 1669 | } | 1599 | } |
| 1670 | expect(gated.pendingInteraction.kind).toBe("form"); | 1600 | expect(gated.pendingInteraction.kind).toBe("form"); |
| 1671 | expect(gated.pendingInteraction.payloadJson).toContain("Allow Create a DNS record?"); | 1601 | expect(gated.pendingInteraction.payloadJson).toContain("Allow records.createRecord?"); |
| 1672 | expect(gated.pendingInteraction.payloadJson).toContain("\"approve\""); | 1602 | expect(gated.pendingInteraction.payloadJson).toContain("\"approve\""); |
| 1673 | 1603 | ||
| 1674 | const approved = yield* client.executions.resume({ | 1604 | const approved = yield* client.executions.resume({ |
| 1675 | path: { | 1605 | path: { |
| 1676 | workspaceId: installation.workspaceId, | 1606 | workspaceId: installation.scopeId, |
| 1677 | executionId: gated.execution.id, | 1607 | executionId: gated.execution.id, |
| 1678 | }, | 1608 | }, |
| 1679 | payload: { | 1609 | payload: { |
| @@ -1691,7 +1621,7 @@ describe("local-executor-server", () => { · 11 unmodified lines | |||
| 1691 | 1621 | ||
| 1692 | const policy = yield* client.policies.create({ | 1622 | const policy = yield* client.policies.create({ |
| 1693 | path: { | 1623 | path: { |
| 1694 | workspaceId: installation.workspaceId, | 1624 | workspaceId: installation.scopeId, |
| 1695 | }, | 1625 | }, |
| 1696 | payload: { | 1626 | payload: { |
| 1697 | resourcePattern: "dns.records.createRecord", | 1627 | resourcePattern: "dns.records.createRecord", |
| @@ -1703,7 +1633,7 @@ describe("local-executor-server", () => { · 5 unmodified lines | |||
| 1703 | 1633 | ||
| 1704 | const automatic = yield* client.executions.create({ | 1634 | const automatic = yield* client.executions.create({ |
| 1705 | path: { | 1635 | path: { |
| 1706 | workspaceId: installation.workspaceId, | 1636 | workspaceId: installation.scopeId, |
| 1707 | }, | 1637 | }, |
| 1708 | payload: { | 1638 | payload: { |
| 1709 | code: 'return await tools.dns.records.createRecord({ body: { type: "TXT", name: "", value: "hello again" } });', | 1639 | code: 'return await tools.dns.records.createRecord({ body: { type: "TXT", name: "", value: "hello again" } });', |
| @@ -1735,11 +1665,11 @@ describe("local-executor-server", () => { · 25 unmodified lines | |||
| 1735 | const installation = yield* bootstrapClient.local.installation({}); | 1665 | const installation = yield* bootstrapClient.local.installation({}); |
| 1736 | 1666 | ||
| 1737 | const startResponse = yield* Effect.promise(() => | 1667 | const startResponse = yield* Effect.promise(() => |
| 1738 | fetch(`${server.baseUrl}/v1/workspaces/${encodeURIComponent(installation.workspaceId)}/oauth/source-auth/start`, { | 1668 | fetch(`${server.baseUrl}/v1/workspaces/${encodeURIComponent(installation.scopeId)}/oauth/source-auth/start`, { |
| 1739 | method: "POST", | 1669 | method: "POST", |
| 1740 | headers: { | 1670 | headers: { |
| 1741 | "content-type": "application/json", | 1671 | "content-type": "application/json", |
| 1742 | "x-executor-account-id": installation.accountId, | 1672 | "x-executor-account-id": installation.actorScopeId, |
| 1743 | }, | 1673 | }, |
| 1744 | body: JSON.stringify({ | 1674 | body: JSON.stringify({ |
| 1745 | provider: "mcp", | 1675 | provider: "mcp", |
| @@ -1774,11 +1704,11 @@ describe("local-executor-server", () => { · 28 unmodified lines | |||
| 1774 | 1704 | ||
| 1775 | const client = yield* createExecutorApiClient({ | 1705 | const client = yield* createExecutorApiClient({ |
| 1776 | baseUrl: server.baseUrl, | 1706 | baseUrl: server.baseUrl, |
| 1777 | accountId: installation.accountId, | 1707 | accountId: installation.actorScopeId, |
| 1778 | }); | 1708 | }); |
| 1779 | const sources = yield* client.sources.list({ | 1709 | const sources = yield* client.sources.list({ |
| 1780 | path: { | 1710 | path: { |
| 1781 | workspaceId: installation.workspaceId, | 1711 | workspaceId: installation.scopeId, |
| 1782 | }, | 1712 | }, |
| 1783 | }); | 1713 | }); |
| 1784 | 1714 | ||
| @@ -1804,7 +1734,7 @@ describe("local-executor-server", () => { · 19 unmodified lines | |||
| 1804 | const installation = yield* bootstrapClient.local.installation({}); | 1734 | const installation = yield* bootstrapClient.local.installation({}); |
| 1805 | const client = yield* createExecutorApiClient({ | 1735 | const client = yield* createExecutorApiClient({ |
| 1806 | baseUrl: server.baseUrl, | 1736 | baseUrl: server.baseUrl, |
| 1807 | accountId: installation.accountId, | 1737 | accountId: installation.actorScopeId, |
| 1808 | }); | 1738 | }); |
| 1809 | yield* writeConfiguredLocalMcpSource({ | 1739 | yield* writeConfiguredLocalMcpSource({ |
| 1810 | workspaceRoot: server.workspaceRoot, | 1740 | workspaceRoot: server.workspaceRoot, |
| @@ -1816,7 +1746,7 @@ describe("local-executor-server", () => { · 5 unmodified lines | |||
| 1816 | 1746 | ||
| 1817 | const execution = yield* client.executions.create({ | 1747 | const execution = yield* client.executions.create({ |
| 1818 | path: { | 1748 | path: { |
| 1819 | workspaceId: installation.workspaceId, | 1749 | workspaceId: installation.scopeId, |
| 1820 | }, | 1750 | }, |
| 1821 | payload: { | 1751 | payload: { |
| 1822 | code: 'return await tools.demo.gated_echo({ value: "broken" });', | 1752 | code: 'return await tools.demo.gated_echo({ value: "broken" });', |
| @@ -1832,7 +1762,7 @@ describe("local-executor-server", () => { · 9 unmodified lines | |||
| 1832 | 1762 | ||
| 1833 | const resumed = yield* client.executions.resume({ | 1763 | const resumed = yield* client.executions.resume({ |
| 1834 | path: { | 1764 | path: { |
| 1835 | workspaceId: installation.workspaceId, | 1765 | workspaceId: installation.scopeId, |
| 1836 | executionId: execution.execution.id, | 1766 | executionId: execution.execution.id, |
| 1837 | }, | 1767 | }, |
| 1838 | payload: { | 1768 | payload: { |
| @@ -484,7 +484,7 @@ const buildConnectPayload = (form: ConnectFormState): ConnectSourcePayload => { · 483 unmodified lines | |||
| 484 | discoveryUrl: trimToNull(form.discoveryUrl), | 484 | discoveryUrl: trimToNull(form.discoveryUrl), |
| 485 | name: trimToNull(form.name), | 485 | name: trimToNull(form.name), |
| 486 | namespace: trimToNull(form.namespace), | 486 | namespace: trimToNull(form.namespace), |
| 487 | workspaceOauthClientId: | 487 | scopeOauthClientId: |
| 488 | form.authKind === "oauth2" && | 488 | form.authKind === "oauth2" && |
| 489 | form.workspaceOauthClientId.trim().length > 0 | 489 | form.workspaceOauthClientId.trim().length > 0 |
| 490 | ? form.workspaceOauthClientId.trim() | 490 | ? form.workspaceOauthClientId.trim() |
| @@ -1114,7 +1114,7 @@ export function AddSourcePage() { · 623 unmodified lines | |||
| 1114 | selectedGoogleTemplateIds.includes(template.id), | 1114 | selectedGoogleTemplateIds.includes(template.id), |
| 1115 | ); | 1115 | ); |
| 1116 | const payload: ConnectSourceBatchPayload = { | 1116 | const payload: ConnectSourceBatchPayload = { |
| 1117 | workspaceOauthClientId: | 1117 | scopeOauthClientId: |
| 1118 | workspaceOauthClientId as WorkspaceOauthClient["id"], | 1118 | workspaceOauthClientId as WorkspaceOauthClient["id"], |
| 1119 | sources: selectedTemplates.map((template) => ({ | 1119 | sources: selectedTemplates.map((template) => ({ |
| 1120 | service: template.service, | 1120 | service: template.service, |
| @@ -36,6 +36,7 @@ · 35 unmodified lines | |||
| 36 | }, | 36 | }, |
| 37 | "devDependencies": { | 37 | "devDependencies": { |
| 38 | "@effect/vitest": "catalog:", | 38 | "@effect/vitest": "catalog:", |
| 39 | "@executor/effect-test-utils": "workspace:*", | ||
| 39 | "@executor/mcp-elicitation-demo": "workspace:*", | 40 | "@executor/mcp-elicitation-demo": "workspace:*", |
| 40 | "@executor/runtime-ses": "workspace:*", | 41 | "@executor/runtime-ses": "workspace:*", |
| 41 | "@modelcontextprotocol/sdk": "^1.26.0", | 42 | "@modelcontextprotocol/sdk": "^1.26.0", |
| @@ -150,6 +151,7 @@ · 108 unmodified lines | |||
| 150 | "@effect/platform": "catalog:", | 151 | "@effect/platform": "catalog:", |
| 151 | "@effect/platform-node": "catalog:", | 152 | "@effect/platform-node": "catalog:", |
| 152 | "@effect/vitest": "catalog:", | 153 | "@effect/vitest": "catalog:", |
| 154 | "@executor/effect-test-utils": "workspace:*", | ||
| 153 | "@executor/platform-sdk-file": "workspace:*", | 155 | "@executor/platform-sdk-file": "workspace:*", |
| 154 | "@types/jsdom": "^21.1.7", | 156 | "@types/jsdom": "^21.1.7", |
| 155 | "@types/node": "catalog:", | 157 | "@types/node": "catalog:", |
| @@ -164,6 +166,20 @@ · 8 unmodified lines | |||
| 164 | "react": ">=18 <20", | 166 | "react": ">=18 <20", |
| 165 | }, | 167 | }, |
| 166 | }, | 168 | }, |
| 169 | "packages/dev/effect-test-utils": { | ||
| 170 | "name": "@executor/effect-test-utils", | ||
| 171 | "version": "0.0.0", | ||
| 172 | "dependencies": { | ||
| 173 | "@effect/platform": "catalog:", | ||
| 174 | "@effect/platform-node": "catalog:", | ||
| 175 | "effect": "catalog:", | ||
| 176 | }, | ||
| 177 | "devDependencies": { | ||
| 178 | "@types/node": "catalog:", | ||
| 179 | "bun-types": "catalog:", | ||
| 180 | "typescript": "^5.9.3", | ||
| 181 | }, | ||
| 182 | }, | ||
| 167 | "packages/dev/kitchen-sink": { | 183 | "packages/dev/kitchen-sink": { |
| 168 | "name": "@executor/kitchen-sink", | 184 | "name": "@executor/kitchen-sink", |
| 169 | "version": "0.0.0", | 185 | "version": "0.0.0", |
| @@ -337,6 +353,7 @@ · 167 unmodified lines | |||
| 337 | }, | 353 | }, |
| 338 | "devDependencies": { | 354 | "devDependencies": { |
| 339 | "@effect/vitest": "catalog:", | 355 | "@effect/vitest": "catalog:", |
| 356 | "@executor/effect-test-utils": "workspace:*", | ||
| 340 | "@modelcontextprotocol/sdk": "^1.26.0", | 357 | "@modelcontextprotocol/sdk": "^1.26.0", |
| 341 | "@types/node": "catalog:", | 358 | "@types/node": "catalog:", |
| 342 | "bun-types": "catalog:", | 359 | "bun-types": "catalog:", |
| @@ -709,6 +726,8 @@ · 366 unmodified lines | |||
| 709 | 726 | ||
| 710 | "@executor/docs": ["@executor/docs@workspace:apps/docs"], | 727 | "@executor/docs": ["@executor/docs@workspace:apps/docs"], |
| 711 | 728 | ||
| 729 | "@executor/effect-test-utils": ["@executor/effect-test-utils@workspace:packages/dev/effect-test-utils"], | ||
| 730 | |||
| 712 | "@executor/executor-mcp": ["@executor/executor-mcp@workspace:packages/hosts/mcp"], | 731 | "@executor/executor-mcp": ["@executor/executor-mcp@workspace:packages/hosts/mcp"], |
| 713 | 732 | ||
| 714 | "@executor/ir": ["@executor/ir@workspace:packages/kernel/ir"], | 733 | "@executor/ir": ["@executor/ir@workspace:packages/kernel/ir"], |
| @@ -5,8 +5,8 @@ const databasePath = process.env.DATABASE_PATH · 4 unmodified lines | |||
| 5 | 5 | ||
| 6 | const executor = await createSqliteExecutor({ | 6 | const executor = await createSqliteExecutor({ |
| 7 | databasePath, | 7 | databasePath, |
| 8 | workspaceName: "SQLite Example Workspace", | 8 | scopeName: "SQLite Example Workspace", |
| 9 | workspaceRoot: process.cwd(), | 9 | scopeRoot: process.cwd(), |
| 10 | }); | 10 | }); |
| 11 | 11 | ||
| 12 | try { | 12 | try { |
| @@ -16,13 +16,13 @@ import { · 15 unmodified lines | |||
| 16 | type ExecutorSecretMaterialBackend, | 16 | type ExecutorSecretMaterialBackend, |
| 17 | type ExecutorSourceArtifactBackend, | 17 | type ExecutorSourceArtifactBackend, |
| 18 | type ExecutorSourceTypeDeclarationsBackend, | 18 | type ExecutorSourceTypeDeclarationsBackend, |
| 19 | type ExecutorWorkspaceConfigBackend, | 19 | type ExecutorScopeConfigBackend, |
| 20 | type ExecutorWorkspaceStateBackend, | 20 | type ExecutorScopeStateBackend, |
| 21 | } from "@executor/platform-sdk"; | 21 | } from "@executor/platform-sdk"; |
| 22 | import type { ExecutorRuntimeOptions } from "@executor/platform-sdk/runtime"; | 22 | import type { ExecutorRuntimeOptions } from "@executor/platform-sdk/runtime"; |
| 23 | import { | 23 | import { |
| 24 | type AuthArtifact, | 24 | type AuthArtifact, |
| 25 | AccountIdSchema, | 25 | ScopeIdSchema, |
| 26 | AuthArtifactSchema, | 26 | AuthArtifactSchema, |
| 27 | type AuthLease, | 27 | type AuthLease, |
| 28 | AuthLeaseSchema, | 28 | AuthLeaseSchema, |
| @@ -43,11 +43,10 @@ import { · 14 unmodified lines | |||
| 43 | SourceAuthSessionSchema, | 43 | SourceAuthSessionSchema, |
| 44 | SourceCatalogIdSchema, | 44 | SourceCatalogIdSchema, |
| 45 | SourceCatalogRevisionIdSchema, | 45 | SourceCatalogRevisionIdSchema, |
| 46 | WorkspaceIdSchema, | 46 | type ScopeOauthClient, |
| 47 | type WorkspaceOauthClient, | 47 | ScopeOauthClientSchema, |
| 48 | WorkspaceOauthClientSchema, | 48 | type ScopedSourceOauthClient, |
| 49 | type WorkspaceSourceOauthClient, | 49 | ScopedSourceOauthClientSchema, |
| 50 | WorkspaceSourceOauthClientSchema, | ||
| 51 | type SecretMaterial, | 50 | type SecretMaterial, |
| 52 | type SecretRef, | 51 | type SecretRef, |
| 53 | } from "@executor/platform-sdk/schema"; | 52 | } from "@executor/platform-sdk/schema"; |
| @@ -59,24 +58,24 @@ import { contentHash, snapshotFromSourceCatalogSyncResult } from "@executor/sour · 5 unmodified lines | |||
| 59 | 58 | ||
| 60 | export type CreateSqliteExecutorBackendOptions = { | 59 | export type CreateSqliteExecutorBackendOptions = { |
| 61 | databasePath?: string; | 60 | databasePath?: string; |
| 62 | workspaceName?: string; | 61 | scopeName?: string; |
| 63 | workspaceRoot?: string | null; | 62 | scopeRoot?: string | null; |
| 64 | workspaceId?: string; | 63 | scopeId?: string; |
| 65 | accountId?: string; | 64 | actorScopeId?: string; |
| 66 | }; | 65 | }; |
| 67 | 66 | ||
| 68 | type DocumentNamespace = | 67 | type DocumentNamespace = |
| 69 | | "installation" | 68 | | "installation" |
| 70 | | "workspace_config" | 69 | | "scope_config" |
| 71 | | "workspace_state" | 70 | | "scope_state" |
| 72 | | "source_artifact" | 71 | | "source_artifact" |
| 73 | | "executor_state"; | 72 | | "executor_state"; |
| 74 | 73 | ||
| 75 | type ExecutorStateCollections = { | 74 | type ExecutorStateCollections = { |
| 76 | authArtifacts: readonly AuthArtifact[]; | 75 | authArtifacts: readonly AuthArtifact[]; |
| 77 | authLeases: readonly AuthLease[]; | 76 | authLeases: readonly AuthLease[]; |
| 78 | sourceOauthClients: readonly WorkspaceSourceOauthClient[]; | 77 | sourceOauthClients: readonly ScopedSourceOauthClient[]; |
| 79 | workspaceOauthClients: readonly WorkspaceOauthClient[]; | 78 | scopeOauthClients: readonly ScopeOauthClient[]; |
| 80 | providerAuthGrants: readonly ProviderAuthGrant[]; | 79 | providerAuthGrants: readonly ProviderAuthGrant[]; |
| 81 | sourceAuthSessions: readonly SourceAuthSession[]; | 80 | sourceAuthSessions: readonly SourceAuthSession[]; |
| 82 | secretMaterials: readonly SecretMaterial[]; | 81 | secretMaterials: readonly SecretMaterial[]; |
| @@ -90,10 +89,10 @@ const decodeConfig = Schema.decodeUnknownSync(LocalExecutorConfigSchema); · 7 unmodified lines | |||
| 90 | const decodeAuthArtifacts = Schema.decodeUnknownSync(Schema.Array(AuthArtifactSchema)); | 89 | const decodeAuthArtifacts = Schema.decodeUnknownSync(Schema.Array(AuthArtifactSchema)); |
| 91 | const decodeAuthLeases = Schema.decodeUnknownSync(Schema.Array(AuthLeaseSchema)); | 90 | const decodeAuthLeases = Schema.decodeUnknownSync(Schema.Array(AuthLeaseSchema)); |
| 92 | const decodeSourceOauthClients = Schema.decodeUnknownSync( | 91 | const decodeSourceOauthClients = Schema.decodeUnknownSync( |
| 93 | Schema.Array(WorkspaceSourceOauthClientSchema), | 92 | Schema.Array(ScopedSourceOauthClientSchema), |
| 94 | ); | 93 | ); |
| 95 | const decodeWorkspaceOauthClients = Schema.decodeUnknownSync( | 94 | const decodeScopeOauthClients = Schema.decodeUnknownSync( |
| 96 | Schema.Array(WorkspaceOauthClientSchema), | 95 | Schema.Array(ScopeOauthClientSchema), |
| 97 | ); | 96 | ); |
| 98 | const decodeProviderAuthGrants = Schema.decodeUnknownSync( | 97 | const decodeProviderAuthGrants = Schema.decodeUnknownSync( |
| 99 | Schema.Array(ProviderAuthGrantSchema), | 98 | Schema.Array(ProviderAuthGrantSchema), |
| @@ -117,10 +116,10 @@ type SourceArtifactBuildInput = Parameters<ExecutorSourceArtifactBackend["build" · 17 unmodified lines | |||
| 117 | 116 | ||
| 118 | const SQLITE_SECRET_PROVIDER_ID = "sqlite"; | 117 | const SQLITE_SECRET_PROVIDER_ID = "sqlite"; |
| 119 | 118 | ||
| 120 | type WorkspaceState = Parameters<ExecutorWorkspaceStateBackend["write"]>[0]; | 119 | type ScopeState = Parameters<ExecutorScopeStateBackend["write"]>[0]; |
| 121 | const defaultProjectConfig = decodeConfig({}); | 120 | const defaultProjectConfig = decodeConfig({}); |
| 122 | 121 | ||
| 123 | const defaultWorkspaceState = (): WorkspaceState => ({ | 122 | const defaultScopeState = (): ScopeState => ({ |
| 124 | version: 1 as const, | 123 | version: 1 as const, |
| 125 | sources: {}, | 124 | sources: {}, |
| 126 | policies: {}, | 125 | policies: {}, |
| @@ -258,8 +257,12 @@ const createInstallationStore = ( · 131 unmodified lines | |||
| 258 | ): ExecutorInstallationBackend => { | 257 | ): ExecutorInstallationBackend => { |
| 259 | const provision = (): LocalInstallation => | 258 | const provision = (): LocalInstallation => |
| 260 | decodeInstallation({ | 259 | decodeInstallation({ |
| 261 | accountId: AccountIdSchema.make(options.accountId ?? "acct_sqlite_example"), | 260 | actorScopeId: ScopeIdSchema.make(options.actorScopeId ?? "acct_sqlite_example"), |
| 262 | workspaceId: WorkspaceIdSchema.make(options.workspaceId ?? "ws_sqlite_example"), | 261 | scopeId: ScopeIdSchema.make(options.scopeId ?? "ws_sqlite_example"), |
| 262 | resolutionScopeIds: [ | ||
| 263 | ScopeIdSchema.make(options.scopeId ?? "ws_sqlite_example"), | ||
| 264 | ScopeIdSchema.make(options.actorScopeId ?? "acct_sqlite_example"), | ||
| 265 | ], | ||
| 263 | }); | 266 | }); |
| 264 | 267 | ||
| 265 | return { | 268 | return { |
| @@ -276,13 +279,13 @@ const createInstallationStore = ( · 10 unmodified lines | |||
| 276 | }; | 279 | }; |
| 277 | }; | 280 | }; |
| 278 | 281 | ||
| 279 | const createWorkspaceConfigStore = ( | 282 | const createScopeConfigStore = ( |
| 280 | store: SqliteDocumentStore, | 283 | store: SqliteDocumentStore, |
| 281 | ): ExecutorWorkspaceConfigBackend => ({ | 284 | ): ExecutorScopeConfigBackend => ({ |
| 282 | load: () => | 285 | load: () => |
| 283 | effectTry("load workspace config", () => { | 286 | effectTry("load workspace config", () => { |
| 284 | const projectConfig = store.read( | 287 | const projectConfig = store.read( |
| 285 | "workspace_config", | 288 | "scope_config", |
| 286 | "project", | 289 | "project", |
| 287 | decodeConfig, | 290 | decodeConfig, |
| 288 | () => defaultProjectConfig, | 291 | () => defaultProjectConfig, |
| @@ -296,22 +299,22 @@ const createWorkspaceConfigStore = ( · 7 unmodified lines | |||
| 296 | }), | 299 | }), |
| 297 | writeProject: (config) => | 300 | writeProject: (config) => |
| 298 | effectTry("write workspace config", () => { | 301 | effectTry("write workspace config", () => { |
| 299 | store.write("workspace_config", "project", config); | 302 | store.write("scope_config", "project", config); |
| 300 | }), | 303 | }), |
| 301 | resolveRelativePath: ({ path, workspaceRoot }) => | 304 | resolveRelativePath: ({ path, scopeRoot }) => |
| 302 | resolvePath(workspaceRoot, path), | 305 | resolvePath(scopeRoot, path), |
| 303 | }); | 306 | }); |
| 304 | 307 | ||
| 305 | const createWorkspaceStateStore = ( | 308 | const createScopeStateStore = ( |
| 306 | store: SqliteDocumentStore, | 309 | store: SqliteDocumentStore, |
| 307 | ): ExecutorWorkspaceStateBackend => ({ | 310 | ): ExecutorScopeStateBackend => ({ |
| 308 | load: () => | 311 | load: () => |
| 309 | effectTry("load workspace state", () => | 312 | effectTry("load workspace state", () => |
| 310 | store.read("workspace_state", "active", (value) => value as ReturnType<typeof defaultWorkspaceState>, defaultWorkspaceState), | 313 | store.read("scope_state", "active", (value) => value as ReturnType<typeof defaultScopeState>, defaultScopeState), |
| 311 | ), | 314 | ), |
| 312 | write: (state) => | 315 | write: (state) => |
| 313 | effectTry("write workspace state", () => { | 316 | effectTry("write workspace state", () => { |
| 314 | store.write("workspace_state", "active", state); | 317 | store.write("scope_state", "active", state); |
| 315 | }), | 318 | }), |
| 316 | }); | 319 | }); |
| 317 | 320 | ||
| @@ -351,8 +354,8 @@ const createExecutorStateStore = ( · 33 unmodified lines | |||
| 351 | return store.read("executor_state", key, decodeAuthLeases, () => []) as ExecutorStateCollections[K]; | 354 | return store.read("executor_state", key, decodeAuthLeases, () => []) as ExecutorStateCollections[K]; |
| 352 | case "sourceOauthClients": | 355 | case "sourceOauthClients": |
| 353 | return store.read("executor_state", key, decodeSourceOauthClients, () => []) as ExecutorStateCollections[K]; | 356 | return store.read("executor_state", key, decodeSourceOauthClients, () => []) as ExecutorStateCollections[K]; |
| 354 | case "workspaceOauthClients": | 357 | case "scopeOauthClients": |
| 355 | return store.read("executor_state", key, decodeWorkspaceOauthClients, () => []) as ExecutorStateCollections[K]; | 358 | return store.read("executor_state", key, decodeScopeOauthClients, () => []) as ExecutorStateCollections[K]; |
| 356 | case "providerAuthGrants": | 359 | case "providerAuthGrants": |
| 357 | return store.read("executor_state", key, decodeProviderAuthGrants, () => []) as ExecutorStateCollections[K]; | 360 | return store.read("executor_state", key, decodeProviderAuthGrants, () => []) as ExecutorStateCollections[K]; |
| 358 | case "sourceAuthSessions": | 361 | case "sourceAuthSessions": |
| @@ -387,23 +390,23 @@ const createExecutorStateStore = ( · 28 unmodified lines | |||
| 387 | 390 | ||
| 388 | return { | 391 | return { |
| 389 | authArtifacts: { | 392 | authArtifacts: { |
| 390 | listByWorkspaceId: (workspaceId) => | 393 | listByScopeId: (scopeId) => |
| 391 | effectTry("list auth artifacts by workspace", () => | 394 | effectTry("list auth artifacts by workspace", () => |
| 392 | readCollection("authArtifacts").filter((item) => item.workspaceId === workspaceId), | 395 | readCollection("authArtifacts").filter((item) => item.scopeId === scopeId), |
| 393 | ), | 396 | ), |
| 394 | listByWorkspaceAndSourceId: ({ workspaceId, sourceId }) => | 397 | listByScopeAndSourceId: ({ scopeId, sourceId }) => |
| 395 | effectTry("list auth artifacts by source", () => | 398 | effectTry("list auth artifacts by source", () => |
| 396 | readCollection("authArtifacts").filter((item) => | 399 | readCollection("authArtifacts").filter((item) => |
| 397 | item.workspaceId === workspaceId && item.sourceId === sourceId | 400 | item.scopeId === scopeId && item.sourceId === sourceId |
| 398 | ), | 401 | ), |
| 399 | ), | 402 | ), |
| 400 | getByWorkspaceSourceAndActor: ({ workspaceId, sourceId, actorAccountId, slot }) => | 403 | getByScopeSourceAndActor: ({ scopeId, sourceId, actorScopeId, slot }) => |
| 401 | effectTry("get auth artifact", () => | 404 | effectTry("get auth artifact", () => |
| 402 | Option.fromNullable( | 405 | Option.fromNullable( |
| 403 | readCollection("authArtifacts").find((item) => | 406 | readCollection("authArtifacts").find((item) => |
| 404 | item.workspaceId === workspaceId | 407 | item.scopeId === scopeId |
| 405 | && item.sourceId === sourceId | 408 | && item.sourceId === sourceId |
| 406 | && sameActor(item.actorAccountId, actorAccountId) | 409 | && sameActor(item.actorScopeId, actorScopeId) |
| 407 | && item.slot === slot | 410 | && item.slot === slot |
| 408 | ), | 411 | ), |
| 409 | ), | 412 | ), |
| @@ -412,9 +415,9 @@ const createExecutorStateStore = ( · 2 unmodified lines | |||
| 412 | effectTry("upsert auth artifact", () => { | 415 | effectTry("upsert auth artifact", () => { |
| 413 | updateCollection("authArtifacts", (items) => { | 416 | updateCollection("authArtifacts", (items) => { |
| 414 | const index = items.findIndex((item) => | 417 | const index = items.findIndex((item) => |
| 415 | item.workspaceId === artifact.workspaceId | 418 | item.scopeId === artifact.scopeId |
| 416 | && item.sourceId === artifact.sourceId | 419 | && item.sourceId === artifact.sourceId |
| 417 | && sameActor(item.actorAccountId, artifact.actorAccountId) | 420 | && sameActor(item.actorScopeId, artifact.actorScopeId) |
| 418 | && item.slot === artifact.slot | 421 | && item.slot === artifact.slot |
| 419 | ); | 422 | ); |
| 420 | if (index >= 0) { | 423 | if (index >= 0) { |
| @@ -424,25 +427,25 @@ const createExecutorStateStore = ( · 3 unmodified lines | |||
| 424 | } | 427 | } |
| 425 | }); | 428 | }); |
| 426 | }), | 429 | }), |
| 427 | removeByWorkspaceSourceAndActor: ({ workspaceId, sourceId, actorAccountId, slot }) => | 430 | removeByScopeSourceAndActor: ({ scopeId, sourceId, actorScopeId, slot }) => |
| 428 | effectTry("remove auth artifact", () => | 431 | effectTry("remove auth artifact", () => |
| 429 | updateCollection("authArtifacts", (items) => { | 432 | updateCollection("authArtifacts", (items) => { |
| 430 | const before = items.length; | 433 | const before = items.length; |
| 431 | const remaining = items.filter((item) => !( | 434 | const remaining = items.filter((item) => !( |
| 432 | item.workspaceId === workspaceId | 435 | item.scopeId === scopeId |
| 433 | && item.sourceId === sourceId | 436 | && item.sourceId === sourceId |
| 434 | && sameActor(item.actorAccountId, actorAccountId) | 437 | && sameActor(item.actorScopeId, actorScopeId) |
| 435 | && (slot === undefined || item.slot === slot) | 438 | && (slot === undefined || item.slot === slot) |
| 436 | )); | 439 | )); |
| 437 | items.splice(0, items.length, ...remaining); | 440 | items.splice(0, items.length, ...remaining); |
| 438 | return before !== remaining.length; | 441 | return before !== remaining.length; |
| 439 | }), | 442 | }), |
| 440 | ), | 443 | ), |
| 441 | removeByWorkspaceAndSourceId: ({ workspaceId, sourceId }) => | 444 | removeByScopeAndSourceId: ({ scopeId, sourceId }) => |
| 442 | effectTry("remove auth artifacts by source", () => | 445 | effectTry("remove auth artifacts by source", () => |
| 443 | updateCollection("authArtifacts", (items) => { | 446 | updateCollection("authArtifacts", (items) => { |
| 444 | const remaining = items.filter((item) => | 447 | const remaining = items.filter((item) => |
| 445 | !(item.workspaceId === workspaceId && item.sourceId === sourceId) | 448 | !(item.scopeId === scopeId && item.sourceId === sourceId) |
| 446 | ); | 449 | ); |
| 447 | const removed = items.length - remaining.length; | 450 | const removed = items.length - remaining.length; |
| 448 | items.splice(0, items.length, ...remaining); | 451 | items.splice(0, items.length, ...remaining); |
| @@ -481,11 +484,11 @@ const createExecutorStateStore = ( · 32 unmodified lines | |||
| 481 | ), | 484 | ), |
| 482 | }, | 485 | }, |
| 483 | sourceOauthClients: { | 486 | sourceOauthClients: { |
| 484 | getByWorkspaceSourceAndProvider: ({ workspaceId, sourceId, providerKey }) => | 487 | getByScopeSourceAndProvider: ({ scopeId, sourceId, providerKey }) => |
| 485 | effectTry("get source oauth client", () => | 488 | effectTry("get source oauth client", () => |
| 486 | Option.fromNullable( | 489 | Option.fromNullable( |
| 487 | readCollection("sourceOauthClients").find((item) => | 490 | readCollection("sourceOauthClients").find((item) => |
| 488 | item.workspaceId === workspaceId | 491 | item.scopeId === scopeId |
| 489 | && item.sourceId === sourceId | 492 | && item.sourceId === sourceId |
| 490 | && item.providerKey === providerKey | 493 | && item.providerKey === providerKey |
| 491 | ), | 494 | ), |
| @@ -495,7 +498,7 @@ const createExecutorStateStore = ( · 3 unmodified lines | |||
| 495 | effectTry("upsert source oauth client", () => { | 498 | effectTry("upsert source oauth client", () => { |
| 496 | updateCollection("sourceOauthClients", (items) => { | 499 | updateCollection("sourceOauthClients", (items) => { |
| 497 | const index = items.findIndex((item) => | 500 | const index = items.findIndex((item) => |
| 498 | item.workspaceId === oauthClient.workspaceId | 501 | item.scopeId === oauthClient.scopeId |
| 499 | && item.sourceId === oauthClient.sourceId | 502 | && item.sourceId === oauthClient.sourceId |
| 500 | && item.providerKey === oauthClient.providerKey | 503 | && item.providerKey === oauthClient.providerKey |
| 501 | ); | 504 | ); |
| @@ -506,11 +509,11 @@ const createExecutorStateStore = ( · 4 unmodified lines | |||
| 506 | } | 509 | } |
| 507 | }); | 510 | }); |
| 508 | }), | 511 | }), |
| 509 | removeByWorkspaceAndSourceId: ({ workspaceId, sourceId }) => | 512 | removeByScopeAndSourceId: ({ scopeId, sourceId }) => |
| 510 | effectTry("remove source oauth clients", () => | 513 | effectTry("remove source oauth clients", () => |
| 511 | updateCollection("sourceOauthClients", (items) => { | 514 | updateCollection("sourceOauthClients", (items) => { |
| 512 | const remaining = items.filter((item) => | 515 | const remaining = items.filter((item) => |
| 513 | !(item.workspaceId === workspaceId && item.sourceId === sourceId) | 516 | !(item.scopeId === scopeId && item.sourceId === sourceId) |
| 514 | ); | 517 | ); |
| 515 | const removed = items.length - remaining.length; | 518 | const removed = items.length - remaining.length; |
| 516 | items.splice(0, items.length, ...remaining); | 519 | items.splice(0, items.length, ...remaining); |
| @@ -518,22 +521,22 @@ const createExecutorStateStore = ( · 1 unmodified line | |||
| 518 | }), | 521 | }), |
| 519 | ), | 522 | ), |
| 520 | }, | 523 | }, |
| 521 | workspaceOauthClients: { | 524 | scopeOauthClients: { |
| 522 | listByWorkspaceAndProvider: ({ workspaceId, providerKey }) => | 525 | listByScopeAndProvider: ({ scopeId, providerKey }) => |
| 523 | effectTry("list workspace oauth clients", () => | 526 | effectTry("list workspace oauth clients", () => |
| 524 | readCollection("workspaceOauthClients").filter((item) => | 527 | readCollection("scopeOauthClients").filter((item) => |
| 525 | item.workspaceId === workspaceId && item.providerKey === providerKey | 528 | item.scopeId === scopeId && item.providerKey === providerKey |
| 526 | ), | 529 | ), |
| 527 | ), | 530 | ), |
| 528 | getById: (id) => | 531 | getById: (id) => |
| 529 | effectTry("get workspace oauth client", () => | 532 | effectTry("get workspace oauth client", () => |
| 530 | Option.fromNullable( | 533 | Option.fromNullable( |
| 531 | readCollection("workspaceOauthClients").find((item) => item.id === id), | 534 | readCollection("scopeOauthClients").find((item) => item.id === id), |
| 532 | ), | 535 | ), |
| 533 | ), | 536 | ), |
| 534 | upsert: (oauthClient) => | 537 | upsert: (oauthClient) => |
| 535 | effectTry("upsert workspace oauth client", () => { | 538 | effectTry("upsert workspace oauth client", () => { |
| 536 | updateCollection("workspaceOauthClients", (items) => { | 539 | updateCollection("scopeOauthClients", (items) => { |
| 537 | const index = items.findIndex((item) => item.id === oauthClient.id); | 540 | const index = items.findIndex((item) => item.id === oauthClient.id); |
| 538 | if (index >= 0) { | 541 | if (index >= 0) { |
| 539 | items[index] = oauthClient; | 542 | items[index] = oauthClient; |
| @@ -544,7 +547,7 @@ const createExecutorStateStore = ( · 4 unmodified lines | |||
| 544 | }), | 547 | }), |
| 545 | removeById: (id) => | 548 | removeById: (id) => |
| 546 | effectTry("remove workspace oauth client", () => | 549 | effectTry("remove workspace oauth client", () => |
| 547 | updateCollection("workspaceOauthClients", (items) => { | 550 | updateCollection("scopeOauthClients", (items) => { |
| 548 | const remaining = items.filter((item) => item.id !== id); | 551 | const remaining = items.filter((item) => item.id !== id); |
| 549 | const removed = remaining.length !== items.length; | 552 | const removed = remaining.length !== items.length; |
| 550 | items.splice(0, items.length, ...remaining); | 553 | items.splice(0, items.length, ...remaining); |
| @@ -553,15 +556,15 @@ const createExecutorStateStore = ( · 2 unmodified lines | |||
| 553 | ), | 556 | ), |
| 554 | }, | 557 | }, |
| 555 | providerAuthGrants: { | 558 | providerAuthGrants: { |
| 556 | listByWorkspaceId: (workspaceId) => | 559 | listByScopeId: (scopeId) => |
| 557 | effectTry("list provider grants by workspace", () => | 560 | effectTry("list provider grants by workspace", () => |
| 558 | readCollection("providerAuthGrants").filter((item) => item.workspaceId === workspaceId), | 561 | readCollection("providerAuthGrants").filter((item) => item.scopeId === scopeId), |
| 559 | ), | 562 | ), |
| 560 | listByWorkspaceActorAndProvider: ({ workspaceId, actorAccountId, providerKey }) => | 563 | listByScopeActorAndProvider: ({ scopeId, actorScopeId, providerKey }) => |
| 561 | effectTry("list provider grants by actor", () => | 564 | effectTry("list provider grants by actor", () => |
| 562 | readCollection("providerAuthGrants").filter((item) => | 565 | readCollection("providerAuthGrants").filter((item) => |
| 563 | item.workspaceId === workspaceId | 566 | item.scopeId === scopeId |
| 564 | && item.actorAccountId === actorAccountId | 567 | && item.actorScopeId === actorScopeId |
| 565 | && item.providerKey === providerKey | 568 | && item.providerKey === providerKey |
| 566 | ), | 569 | ), |
| 567 | ), | 570 | ), |
| @@ -595,9 +598,9 @@ const createExecutorStateStore = ( · 27 unmodified lines | |||
| 595 | sourceAuthSessions: { | 598 | sourceAuthSessions: { |
| 596 | listAll: () => | 599 | listAll: () => |
| 597 | effectTry("list source auth sessions", () => readCollection("sourceAuthSessions")), | 600 | effectTry("list source auth sessions", () => readCollection("sourceAuthSessions")), |
| 598 | listByWorkspaceId: (workspaceId) => | 601 | listByScopeId: (scopeId) => |
| 599 | effectTry("list source auth sessions by workspace", () => | 602 | effectTry("list source auth sessions by workspace", () => |
| 600 | readCollection("sourceAuthSessions").filter((item) => item.workspaceId === workspaceId), | 603 | readCollection("sourceAuthSessions").filter((item) => item.scopeId === scopeId), |
| 601 | ), | 604 | ), |
| 602 | getById: (id) => | 605 | getById: (id) => |
| 603 | effectTry("get source auth session", () => | 606 | effectTry("get source auth session", () => |
| @@ -611,13 +614,13 @@ const createExecutorStateStore = ( · 7 unmodified lines | |||
| 611 | readCollection("sourceAuthSessions").find((item) => item.state === state), | 614 | readCollection("sourceAuthSessions").find((item) => item.state === state), |
| 612 | ), | 615 | ), |
| 613 | ), | 616 | ), |
| 614 | getPendingByWorkspaceSourceAndActor: ({ workspaceId, sourceId, actorAccountId, credentialSlot }) => | 617 | getPendingByScopeSourceAndActor: ({ scopeId, sourceId, actorScopeId, credentialSlot }) => |
| 615 | effectTry("get pending source auth session", () => | 618 | effectTry("get pending source auth session", () => |
| 616 | Option.fromNullable( | 619 | Option.fromNullable( |
| 617 | readCollection("sourceAuthSessions").find((item) => | 620 | readCollection("sourceAuthSessions").find((item) => |
| 618 | item.workspaceId === workspaceId | 621 | item.scopeId === scopeId |
| 619 | && item.sourceId === sourceId | 622 | && item.sourceId === sourceId |
| 620 | && item.actorAccountId === actorAccountId | 623 | && item.actorScopeId === actorScopeId |
| 621 | && item.status === "pending" | 624 | && item.status === "pending" |
| 622 | && (credentialSlot === undefined || item.credentialSlot === credentialSlot) | 625 | && (credentialSlot === undefined || item.credentialSlot === credentialSlot) |
| 623 | ), | 626 | ), |
| @@ -656,11 +659,11 @@ const createExecutorStateStore = ( · 32 unmodified lines | |||
| 656 | } | 659 | } |
| 657 | }); | 660 | }); |
| 658 | }), | 661 | }), |
| 659 | removeByWorkspaceAndSourceId: (workspaceId, sourceId) => | 662 | removeByScopeAndSourceId: (scopeId, sourceId) => |
| 660 | effectTry("remove source auth sessions", () => | 663 | effectTry("remove source auth sessions", () => |
| 661 | updateCollection("sourceAuthSessions", (items) => { | 664 | updateCollection("sourceAuthSessions", (items) => { |
| 662 | const remaining = items.filter((item) => | 665 | const remaining = items.filter((item) => |
| 663 | !(item.workspaceId === workspaceId && item.sourceId === sourceId) | 666 | !(item.scopeId === scopeId && item.sourceId === sourceId) |
| 664 | ); | 667 | ); |
| 665 | const removed = remaining.length !== items.length; | 668 | const removed = remaining.length !== items.length; |
| 666 | items.splice(0, items.length, ...remaining); | 669 | items.splice(0, items.length, ...remaining); |
| @@ -739,11 +742,11 @@ const createExecutorStateStore = ( · 72 unmodified lines | |||
| 739 | readCollection("executions").find((item) => item.id === executionId), | 742 | readCollection("executions").find((item) => item.id === executionId), |
| 740 | ), | 743 | ), |
| 741 | ), | 744 | ), |
| 742 | getByWorkspaceAndId: (workspaceId, executionId) => | 745 | getByScopeAndId: (scopeId, executionId) => |
| 743 | effectTry("get execution by workspace and id", () => | 746 | effectTry("get execution by scope and id", () => |
| 744 | Option.fromNullable( | 747 | Option.fromNullable( |
| 745 | readCollection("executions").find((item) => | 748 | readCollection("executions").find((item) => |
| 746 | item.workspaceId === workspaceId && item.id === executionId | 749 | item.scopeId === scopeId && item.id === executionId |
| 747 | ), | 750 | ), |
| 748 | ), | 751 | ), |
| 749 | ), | 752 | ), |
| @@ -932,9 +935,9 @@ export const createSqliteExecutorBackend = ( · 182 unmodified lines | |||
| 932 | const secretMaterial = createSecretMaterialBackend(executorState); | 935 | const secretMaterial = createSecretMaterialBackend(executorState); |
| 933 | 936 | ||
| 934 | return { | 937 | return { |
| 935 | workspace: { | 938 | scope: { |
| 936 | workspaceName: options.workspaceName ?? "SQLite SDK Example", | 939 | scopeName: options.scopeName ?? "SQLite SDK Example", |
| 937 | workspaceRoot: options.workspaceRoot ?? null, | 940 | scopeRoot: options.scopeRoot ?? null, |
| 938 | metadata: { | 941 | metadata: { |
| 939 | kind: "sqlite", | 942 | kind: "sqlite", |
| 940 | databasePath, | 943 | databasePath, |
| @@ -942,8 +945,8 @@ export const createSqliteExecutorBackend = ( · 1 unmodified line | |||
| 942 | }, | 945 | }, |
| 943 | storage: { | 946 | storage: { |
| 944 | installation: createInstallationStore(store, options), | 947 | installation: createInstallationStore(store, options), |
| 945 | workspaceConfig: createWorkspaceConfigStore(store), | 948 | scopeConfig: createScopeConfigStore(store), |
| 946 | workspaceState: createWorkspaceStateStore(store), | 949 | scopeState: createScopeStateStore(store), |
| 947 | sourceArtifacts: createSourceArtifactStore(store), | 950 | sourceArtifacts: createSourceArtifactStore(store), |
| 948 | executorState, | 951 | executorState, |
| 949 | secretMaterial, | 952 | secretMaterial, |
| @@ -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/effect-test-utils": "workspace:*", | ||
| 27 | "@executor/platform-sdk-file": "workspace:*", | 28 | "@executor/platform-sdk-file": "workspace:*", |
| 28 | "@types/jsdom": "^21.1.7", | 29 | "@types/jsdom": "^21.1.7", |
| 29 | "@types/node": "catalog:", | 30 | "@types/node": "catalog:", |
| @@ -1,8 +1,19 @@ | |||
| 1 | import { createServer } from "node:http"; | 1 | import { createServer } from "node:http"; |
| 2 | 2 | ||
| 3 | import { FileSystem, HttpApiBuilder, HttpServer } from "@effect/platform"; | 3 | import { |
| 4 | FileSystem, | ||
| 5 | HttpApi, | ||
| 6 | HttpApiBuilder, | ||
| 7 | HttpApiEndpoint, | ||
| 8 | HttpApiGroup, | ||
| 9 | HttpServer, | ||
| 10 | OpenApi, | ||
| 11 | } from "@effect/platform"; | ||
| 4 | import { NodeFileSystem, NodeHttpServer } from "@effect/platform-node"; | 12 | import { NodeFileSystem, NodeHttpServer } from "@effect/platform-node"; |
| 5 | import { describe, expect, it } from "@effect/vitest"; | 13 | import { describe, expect, it } from "@effect/vitest"; |
| 14 | import { | ||
| 15 | startOpenApiTestServer, | ||
| 16 | } from "@executor/effect-test-utils"; | ||
| 6 | import { | 17 | import { |
| 7 | createExecutorApiLayer, | 18 | createExecutorApiLayer, |
| 8 | } from "@executor/platform-api"; | 19 | } from "@executor/platform-api"; |
| @@ -17,6 +28,7 @@ import * as Context from "effect/Context"; · 8 unmodified lines | |||
| 17 | import * as Effect from "effect/Effect"; | 28 | import * as Effect from "effect/Effect"; |
| 18 | import * as Exit from "effect/Exit"; | 29 | import * as Exit from "effect/Exit"; |
| 19 | import * as Layer from "effect/Layer"; | 30 | import * as Layer from "effect/Layer"; |
| 31 | import * as Schema from "effect/Schema"; | ||
| 20 | import * as Scope from "effect/Scope"; | 32 | import * as Scope from "effect/Scope"; |
| 21 | import { JSDOM } from "jsdom"; | 33 | import { JSDOM } from "jsdom"; |
| 22 | import * as React from "react"; | 34 | import * as React from "react"; |
| @@ -225,83 +237,38 @@ type OpenApiSpecServer = RunningServer & { · 202 unmodified lines | |||
| 225 | specUrl: string; | 237 | specUrl: string; |
| 226 | }; | 238 | }; |
| 227 | 239 | ||
| 228 | const startOpenApiSpecServer = async (): Promise<OpenApiSpecServer> => { | 240 | class HooksTestPingApi extends HttpApiGroup.make("ping") |
| 229 | const spec = { | 241 | .add( |
| 230 | openapi: "3.0.3", | 242 | HttpApiEndpoint.get("ping")`/ping` |
| 231 | info: { | 243 | .addSuccess( |
| 232 | title: "Hook Test API", | 244 | Schema.Struct({ |
| 233 | version: "1.0.0", | 245 | ok: Schema.Boolean, |
| 234 | }, | 246 | }), |
| 235 | paths: { | 247 | ), |
| 236 | "/ping": { | 248 | ) |
| 237 | get: { | 249 | {} |
| 238 | operationId: "ping", | 250 | |
| 239 | responses: { | 251 | class HooksTestOpenApi extends HttpApi.make("hooksTest").add(HooksTestPingApi) {} |
| 240 | 200: { | 252 | |
| 241 | description: "ok", | 253 | const hooksTestOpenApiSpec = OpenApi.fromApi(HooksTestOpenApi); |
| 242 | content: { | 254 | const hooksTestOpenApiLive = HttpApiBuilder.group( |
| 243 | "application/json": { | 255 | HooksTestOpenApi, |
| 244 | schema: { | 256 | "ping", |
| 245 | type: "object", | 257 | (handlers) => |
| 246 | properties: { | 258 | handlers.handle("ping", () => |
| 247 | ok: { type: "boolean" }, | 259 | Effect.succeed({ |
| 248 | }, | 260 | ok: true, |
| 249 | }, | 261 | }), |
| 250 | }, | 262 | ), |
| 251 | }, | 263 | ); |
| 252 | }, | 264 | const hooksTestOpenApiLayer = HttpApiBuilder.api(HooksTestOpenApi).pipe( |
| 253 | }, | 265 | Layer.provide(hooksTestOpenApiLive), |
| 254 | }, | 266 | ); |
| 255 | }, | ||
| 256 | }, | ||
| 257 | }; | ||
| 258 | |||
| 259 | const server = createServer((req, res) => { | ||
| 260 | if (req.url === "/openapi.json") { | ||
| 261 | res.statusCode = 200; | ||
| 262 | res.setHeader("content-type", "application/json"); | ||
| 263 | res.end(JSON.stringify(spec)); | ||
| 264 | return; | ||
| 265 | } | ||
| 266 | |||
| 267 | if (req.url === "/ping") { | ||
| 268 | res.statusCode = 200; | ||
| 269 | res.setHeader("content-type", "application/json"); | ||
| 270 | res.end(JSON.stringify({ ok: true })); | ||
| 271 | return; | ||
| 272 | } | ||
| 273 | |||
| 274 | res.statusCode = 404; | ||
| 275 | res.end("not found"); | ||
| 276 | }); | ||
| 277 | 267 | ||
| 278 | await new Promise<void>((resolve, reject) => { | 268 | const startOpenApiSpecServer = async (): Promise<OpenApiSpecServer> => { |
| 279 | server.once("error", reject); | 269 | return startOpenApiTestServer({ |
| 280 | server.listen(0, "127.0.0.1", () => resolve()); | 270 | apiLayer: hooksTestOpenApiLayer, |
| 281 | }); | 271 | }); |
| 282 | |||
| 283 | const address = server.address(); | ||
| 284 | if (!address || typeof address === "string") { | ||
| 285 | throw new Error("Failed to bind OpenAPI spec server"); | ||
| 286 | } | ||
| 287 | |||
| 288 | const baseUrl = `http://127.0.0.1:${address.port}`; | ||
| 289 | |||
| 290 | return { | ||
| 291 | baseUrl, | ||
| 292 | specUrl: `${baseUrl}/openapi.json`, | ||
| 293 | close: () => | ||
| 294 | new Promise<void>((resolve, reject) => { | ||
| 295 | server.close((error) => { | ||
| 296 | if (error) { | ||
| 297 | reject(error); | ||
| 298 | return; | ||
| 299 | } | ||
| 300 | |||
| 301 | resolve(); | ||
| 302 | }); | ||
| 303 | }), | ||
| 304 | }; | ||
| 305 | }; | 272 | }; |
| 306 | 273 | ||
| 307 | async function requestJson<T>(input: { | 274 | async function requestJson<T>(input: { |
| @@ -343,42 +310,14 @@ const seedStoredOpenApiSource = async (input: { · 35 unmodified lines | |||
| 343 | name: string; | 310 | name: string; |
| 344 | specUrl?: string; | 311 | specUrl?: string; |
| 345 | }): Promise<Source> => { | 312 | }): Promise<Source> => { |
| 346 | const sourceDocumentText = JSON.stringify({ | 313 | const sourceDocumentText = JSON.stringify(hooksTestOpenApiSpec); |
| 347 | openapi: "3.0.3", | ||
| 348 | info: { | ||
| 349 | title: input.name, | ||
| 350 | version: "1.0.0", | ||
| 351 | }, | ||
| 352 | paths: { | ||
| 353 | "/ping": { | ||
| 354 | get: { | ||
| 355 | operationId: "ping", | ||
| 356 | responses: { | ||
| 357 | 200: { | ||
| 358 | description: "ok", | ||
| 359 | content: { | ||
| 360 | "application/json": { | ||
| 361 | schema: { | ||
| 362 | type: "object", | ||
| 363 | properties: { | ||
| 364 | ok: { type: "boolean" }, | ||
| 365 | }, | ||
| 366 | }, | ||
| 367 | }, | ||
| 368 | }, | ||
| 369 | }, | ||
| 370 | }, | ||
| 371 | }, | ||
| 372 | }, | ||
| 373 | }, | ||
| 374 | }); | ||
| 375 | const specUrl = input.specUrl ?? `data:application/json,${encodeURIComponent(sourceDocumentText)}`; | 314 | const specUrl = input.specUrl ?? `data:application/json,${encodeURIComponent(sourceDocumentText)}`; |
| 376 | 315 | ||
| 377 | return requestJson<Source>({ | 316 | return requestJson<Source>({ |
| 378 | baseUrl: input.server.baseUrl, | 317 | baseUrl: input.server.baseUrl, |
| 379 | path: `/v1/workspaces/${input.installation.workspaceId}/sources`, | 318 | path: `/v1/workspaces/${input.installation.scopeId}/sources`, |
| 380 | method: "POST", | 319 | method: "POST", |
| 381 | accountId: input.installation.accountId, | 320 | accountId: input.installation.actorScopeId, |
| 382 | payload: { | 321 | payload: { |
| 383 | name: input.name, | 322 | name: input.name, |
| 384 | kind: "openapi", | 323 | kind: "openapi", |
| @@ -32,7 +32,7 @@ import type { · 31 unmodified lines | |||
| 32 | SourceInspection, | 32 | SourceInspection, |
| 33 | SourceInspectionDiscoverResult, | 33 | SourceInspectionDiscoverResult, |
| 34 | SourceInspectionToolDetail, | 34 | SourceInspectionToolDetail, |
| 35 | WorkspaceOauthClient, | 35 | ScopeOauthClient as WorkspaceOauthClient, |
| 36 | } from "@executor/platform-sdk/schema"; | 36 | } from "@executor/platform-sdk/schema"; |
| 37 | import * as Cause from "effect/Cause"; | 37 | import * as Cause from "effect/Cause"; |
| 38 | import * as Effect from "effect/Effect"; | 38 | import * as Effect from "effect/Effect"; |
| @@ -42,7 +42,7 @@ import * as Runtime from "effect/Runtime"; · 3 unmodified lines | |||
| 42 | import * as React from "react"; | 42 | import * as React from "react"; |
| 43 | 43 | ||
| 44 | const DEFAULT_EXECUTOR_API_BASE_URL = "http://127.0.0.1:8788"; | 44 | const DEFAULT_EXECUTOR_API_BASE_URL = "http://127.0.0.1:8788"; |
| 45 | const PLACEHOLDER_WORKSPACE_ID = "ws_placeholder" as Source["workspaceId"]; | 45 | const PLACEHOLDER_WORKSPACE_ID = "ws_placeholder" as Source["scopeId"]; |
| 46 | const PLACEHOLDER_ACCOUNT_ID = "acc_placeholder"; | 46 | const PLACEHOLDER_ACCOUNT_ID = "acc_placeholder"; |
| 47 | const PLACEHOLDER_SOURCE_ID = "src_placeholder" as Source["id"]; | 47 | const PLACEHOLDER_SOURCE_ID = "src_placeholder" as Source["id"]; |
| 48 | 48 | ||
| @@ -58,18 +58,18 @@ export type SourceRemoveResult = { · 9 unmodified lines | |||
| 58 | 58 | ||
| 59 | type AtomKeyPart = string | number | boolean | null | undefined; | 59 | type AtomKeyPart = string | number | boolean | null | undefined; |
| 60 | 60 | ||
| 61 | type SourcesKeyParts = readonly [boolean, Source["workspaceId"], string]; | 61 | type SourcesKeyParts = readonly [boolean, Source["scopeId"], string]; |
| 62 | type SourceKeyParts = readonly [boolean, Source["workspaceId"], string, Source["id"]]; | 62 | type SourceKeyParts = readonly [boolean, Source["scopeId"], string, Source["id"]]; |
| 63 | type SourceToolDetailKeyParts = readonly [ | 63 | type SourceToolDetailKeyParts = readonly [ |
| 64 | boolean, | 64 | boolean, |
| 65 | Source["workspaceId"], | 65 | Source["scopeId"], |
| 66 | string, | 66 | string, |
| 67 | Source["id"], | 67 | Source["id"], |
| 68 | string | null, | 68 | string | null, |
| 69 | ]; | 69 | ]; |
| 70 | type SourceDiscoveryKeyParts = readonly [ | 70 | type SourceDiscoveryKeyParts = readonly [ |
| 71 | boolean, | 71 | boolean, |
| 72 | Source["workspaceId"], | 72 | Source["scopeId"], |
| 73 | string, | 73 | string, |
| 74 | Source["id"], | 74 | Source["id"], |
| 75 | string, | 75 | string, |
| @@ -77,13 +77,13 @@ type SourceDiscoveryKeyParts = readonly [ · 1 unmodified line | |||
| 77 | ]; | 77 | ]; |
| 78 | type WorkspaceOauthClientsKeyParts = readonly [ | 78 | type WorkspaceOauthClientsKeyParts = readonly [ |
| 79 | boolean, | 79 | boolean, |
| 80 | Source["workspaceId"], | 80 | Source["scopeId"], |
| 81 | string, | 81 | string, |
| 82 | string, | 82 | string, |
| 83 | ]; | 83 | ]; |
| 84 | 84 | ||
| 85 | type InvalidationTarget = { | 85 | type InvalidationTarget = { |
| 86 | workspaceId?: Source["workspaceId"]; | 86 | workspaceId?: Source["scopeId"]; |
| 87 | accountId?: string; | 87 | accountId?: string; |
| 88 | sourceId?: Source["id"]; | 88 | sourceId?: Source["id"]; |
| 89 | }; | 89 | }; |
| @@ -104,7 +104,7 @@ type ExecutorQueryContextValue = { · 14 unmodified lines | |||
| 104 | }; | 104 | }; |
| 105 | 105 | ||
| 106 | type MutationExecutionContext = { | 106 | type MutationExecutionContext = { |
| 107 | workspaceId: Source["workspaceId"]; | 107 | workspaceId: Source["scopeId"]; |
| 108 | accountId: string; | 108 | accountId: string; |
| 109 | registry: Registry.Registry; | 109 | registry: Registry.Registry; |
| 110 | invalidateQueries: (target?: InvalidationTarget) => void; | 110 | invalidateQueries: (target?: InvalidationTarget) => void; |
| @@ -149,20 +149,20 @@ const decodeAtomKey = <T extends ReadonlyArray<AtomKeyPart>>(key: string): T => · 38 unmodified lines | |||
| 149 | 149 | ||
| 150 | const encodeSourcesKey = ( | 150 | const encodeSourcesKey = ( |
| 151 | enabled: boolean, | 151 | enabled: boolean, |
| 152 | workspaceId: Source["workspaceId"], | 152 | workspaceId: Source["scopeId"], |
| 153 | accountId: string, | 153 | accountId: string, |
| 154 | ): string => encodeAtomKey([enabled, workspaceId, accountId] satisfies SourcesKeyParts); | 154 | ): string => encodeAtomKey([enabled, workspaceId, accountId] satisfies SourcesKeyParts); |
| 155 | 155 | ||
| 156 | const encodeSourceKey = ( | 156 | const encodeSourceKey = ( |
| 157 | enabled: boolean, | 157 | enabled: boolean, |
| 158 | workspaceId: Source["workspaceId"], | 158 | workspaceId: Source["scopeId"], |
| 159 | accountId: string, | 159 | accountId: string, |
| 160 | sourceId: Source["id"], | 160 | sourceId: Source["id"], |
| 161 | ): string => encodeAtomKey([enabled, workspaceId, accountId, sourceId] satisfies SourceKeyParts); | 161 | ): string => encodeAtomKey([enabled, workspaceId, accountId, sourceId] satisfies SourceKeyParts); |
| 162 | 162 | ||
| 163 | const encodeToolDetailKey = ( | 163 | const encodeToolDetailKey = ( |
| 164 | enabled: boolean, | 164 | enabled: boolean, |
| 165 | workspaceId: Source["workspaceId"], | 165 | workspaceId: Source["scopeId"], |
| 166 | accountId: string, | 166 | accountId: string, |
| 167 | sourceId: Source["id"], | 167 | sourceId: Source["id"], |
| 168 | toolPath: string | null, | 168 | toolPath: string | null, |
| @@ -171,7 +171,7 @@ const encodeToolDetailKey = ( · 2 unmodified lines | |||
| 171 | 171 | ||
| 172 | const encodeDiscoveryKey = ( | 172 | const encodeDiscoveryKey = ( |
| 173 | enabled: boolean, | 173 | enabled: boolean, |
| 174 | workspaceId: Source["workspaceId"], | 174 | workspaceId: Source["scopeId"], |
| 175 | accountId: string, | 175 | accountId: string, |
| 176 | sourceId: Source["id"], | 176 | sourceId: Source["id"], |
| 177 | query: string, | 177 | query: string, |
| @@ -181,7 +181,7 @@ const encodeDiscoveryKey = ( · 3 unmodified lines | |||
| 181 | 181 | ||
| 182 | const encodeWorkspaceOauthClientsKey = ( | 182 | const encodeWorkspaceOauthClientsKey = ( |
| 183 | enabled: boolean, | 183 | enabled: boolean, |
| 184 | workspaceId: Source["workspaceId"], | 184 | workspaceId: Source["scopeId"], |
| 185 | accountId: string, | 185 | accountId: string, |
| 186 | providerKey: string, | 186 | providerKey: string, |
| 187 | ): string => | 187 | ): string => |
| @@ -430,7 +430,7 @@ export type Loadable<T> = · 242 unmodified lines | |||
| 430 | 430 | ||
| 431 | type WorkspaceContext = { | 431 | type WorkspaceContext = { |
| 432 | installation: LocalInstallation; | 432 | installation: LocalInstallation; |
| 433 | workspaceId: Source["workspaceId"]; | 433 | workspaceId: Source["scopeId"]; |
| 434 | accountId: string; | 434 | accountId: string; |
| 435 | }; | 435 | }; |
| 436 | 436 | ||
| @@ -483,8 +483,8 @@ const useWorkspaceContext = (): Loadable<WorkspaceContext> => { · 46 unmodified lines | |||
| 483 | status: "ready", | 483 | status: "ready", |
| 484 | data: { | 484 | data: { |
| 485 | installation: installation.data, | 485 | installation: installation.data, |
| 486 | workspaceId: installation.data.workspaceId, | 486 | workspaceId: installation.data.scopeId, |
| 487 | accountId: installation.data.accountId, | 487 | accountId: installation.data.actorScopeId, |
| 488 | }, | 488 | }, |
| 489 | } satisfies Loadable<WorkspaceContext>; | 489 | } satisfies Loadable<WorkspaceContext>; |
| 490 | }, [installation]); | 490 | }, [installation]); |
| @@ -559,7 +559,7 @@ const createActiveQueryCollections = (): ActiveQueryCollections => ({ · 68 unmodified lines | |||
| 559 | 559 | ||
| 560 | const targetMatches = ( | 560 | const targetMatches = ( |
| 561 | target: InvalidationTarget | undefined, | 561 | target: InvalidationTarget | undefined, |
| 562 | workspaceId: Source["workspaceId"], | 562 | workspaceId: Source["scopeId"], |
| 563 | accountId: string, | 563 | accountId: string, |
| 564 | sourceId?: Source["id"], | 564 | sourceId?: Source["id"], |
| 565 | ): boolean => { | 565 | ): boolean => { |
| @@ -671,14 +671,14 @@ const removeSourceFromList = ( · 105 unmodified lines | |||
| 671 | ): ReadonlyArray<Source> => sources.filter((source) => source.id !== sourceId); | 671 | ): ReadonlyArray<Source> => sources.filter((source) => source.id !== sourceId); |
| 672 | 672 | ||
| 673 | const createOptimisticSource = (input: { | 673 | const createOptimisticSource = (input: { |
| 674 | workspaceId: Source["workspaceId"]; | 674 | workspaceId: Source["scopeId"]; |
| 675 | payload: CreateSourcePayload; | 675 | payload: CreateSourcePayload; |
| 676 | }): Source => { | 676 | }): Source => { |
| 677 | const now = Date.now(); | 677 | const now = Date.now(); |
| 678 | 678 | ||
| 679 | return { | 679 | return { |
| 680 | id: `src_optimistic_${crypto.randomUUID()}` as Source["id"], | 680 | id: `src_optimistic_${crypto.randomUUID()}` as Source["id"], |
| 681 | workspaceId: input.workspaceId, | 681 | scopeId: input.workspaceId, |
| 682 | name: input.payload.name, | 682 | name: input.payload.name, |
| 683 | kind: input.payload.kind, | 683 | kind: input.payload.kind, |
| 684 | endpoint: input.payload.endpoint, | 684 | endpoint: input.payload.endpoint, |
| @@ -713,7 +713,7 @@ const applyUpdatePayloadToSource = (source: Source, payload: UpdateSourcePayload · 28 unmodified lines | |||
| 713 | 713 | ||
| 714 | const useSourceMutation = <TInput, TOutput, TOptimistic = never>( | 714 | const useSourceMutation = <TInput, TOutput, TOptimistic = never>( |
| 715 | execute: (input: { | 715 | execute: (input: { |
| 716 | workspaceId: Source["workspaceId"]; | 716 | workspaceId: Source["scopeId"]; |
| 717 | accountId: string; | 717 | accountId: string; |
| 718 | payload: TInput; | 718 | payload: TInput; |
| 719 | }) => Promise<TOutput>, | 719 | }) => Promise<TOutput>, |
| @@ -0,0 +1,22 @@ | |||
| 1 | { | ||
| 2 | "name": "@executor/effect-test-utils", | ||
| 3 | "private": true, | ||
| 4 | "type": "module", | ||
| 5 | "exports": { | ||
| 6 | ".": "./src/index.ts" | ||
| 7 | }, | ||
| 8 | "scripts": { | ||
| 9 | "typecheck": "bunx tsc --noEmit -p tsconfig.json" | ||
| 10 | }, | ||
| 11 | "dependencies": { | ||
| 12 | "@effect/platform": "catalog:", | ||
| 13 | "@effect/platform-node": "catalog:", | ||
| 14 | "effect": "catalog:" | ||
| 15 | }, | ||
| 16 | "devDependencies": { | ||
| 17 | "@types/node": "catalog:", | ||
| 18 | "bun-types": "catalog:", | ||
| 19 | "typescript": "^5.9.3" | ||
| 20 | }, | ||
| 21 | "version": "0.0.0" | ||
| 22 | } | ||
| @@ -0,0 +1,103 @@ | |||
| 1 | import { createServer } from "node:http"; | ||
| 2 | |||
| 3 | import { HttpApiBuilder, HttpServer } from "@effect/platform"; | ||
| 4 | import { NodeHttpServer } from "@effect/platform-node"; | ||
| 5 | import * as Context from "effect/Context"; | ||
| 6 | import * as Effect from "effect/Effect"; | ||
| 7 | import * as Exit from "effect/Exit"; | ||
| 8 | import * as Layer from "effect/Layer"; | ||
| 9 | import * as Scope from "effect/Scope"; | ||
| 10 | |||
| 11 | export type RunningHttpApiTestServer = { | ||
| 12 | baseUrl: string; | ||
| 13 | close: () => Promise<void>; | ||
| 14 | }; | ||
| 15 | |||
| 16 | export type RunningOpenApiTestServer = RunningHttpApiTestServer & { | ||
| 17 | specUrl: string; | ||
| 18 | }; | ||
| 19 | |||
| 20 | type TestApiLayer = Layer.Layer<any, any, never>; | ||
| 21 | |||
| 22 | type HttpApiTestServerOptions = { | ||
| 23 | apiLayer: TestApiLayer; | ||
| 24 | host?: string; | ||
| 25 | openApiPath?: `/${string}`; | ||
| 26 | }; | ||
| 27 | |||
| 28 | const createHttpApiServerLayer = (options: HttpApiTestServerOptions) => { | ||
| 29 | const host = options.host ?? "127.0.0.1"; | ||
| 30 | const openApiPath = options.openApiPath; | ||
| 31 | const apiLayerWithOpenApi = | ||
| 32 | openApiPath === undefined | ||
| 33 | ? options.apiLayer | ||
| 34 | : Layer.mergeAll( | ||
| 35 | options.apiLayer, | ||
| 36 | HttpApiBuilder.middlewareOpenApi({ path: openApiPath }).pipe( | ||
| 37 | Layer.provideMerge(options.apiLayer), | ||
| 38 | ), | ||
| 39 | ); | ||
| 40 | |||
| 41 | return HttpApiBuilder.serve().pipe( | ||
| 42 | Layer.provide(apiLayerWithOpenApi), | ||
| 43 | Layer.provideMerge( | ||
| 44 | NodeHttpServer.layer(() => createServer(), { | ||
| 45 | port: 0, | ||
| 46 | host, | ||
| 47 | }), | ||
| 48 | ), | ||
| 49 | ); | ||
| 50 | }; | ||
| 51 | |||
| 52 | export const startHttpApiTestServer = async ( | ||
| 53 | options: HttpApiTestServerOptions, | ||
| 54 | ): Promise<RunningHttpApiTestServer> => { | ||
| 55 | const scope = await Effect.runPromise(Scope.make()); | ||
| 56 | |||
| 57 | try { | ||
| 58 | const context = await Effect.runPromise( | ||
| 59 | Layer.buildWithScope(createHttpApiServerLayer(options), scope), | ||
| 60 | ); | ||
| 61 | const server = Context.get(context, HttpServer.HttpServer); | ||
| 62 | const baseUrl = HttpServer.formatAddress(server.address); | ||
| 63 | |||
| 64 | return { | ||
| 65 | baseUrl, | ||
| 66 | close: () => Effect.runPromise(Scope.close(scope, Exit.void)), | ||
| 67 | }; | ||
| 68 | } catch (error) { | ||
| 69 | await Effect.runPromise(Scope.close(scope, Exit.void)); | ||
| 70 | throw error; | ||
| 71 | } | ||
| 72 | }; | ||
| 73 | |||
| 74 | export const startOpenApiTestServer = async ( | ||
| 75 | options: HttpApiTestServerOptions, | ||
| 76 | ): Promise<RunningOpenApiTestServer> => { | ||
| 77 | const openApiPath = options.openApiPath ?? "/openapi.json"; | ||
| 78 | const server = await startHttpApiTestServer({ | ||
| 79 | ...options, | ||
| 80 | openApiPath, | ||
| 81 | }); | ||
| 82 | |||
| 83 | return { | ||
| 84 | ...server, | ||
| 85 | specUrl: `${server.baseUrl}${openApiPath}`, | ||
| 86 | }; | ||
| 87 | }; | ||
| 88 | |||
| 89 | export const makeHttpApiTestServer = ( | ||
| 90 | options: HttpApiTestServerOptions, | ||
| 91 | ): Effect.Effect<RunningHttpApiTestServer, never, Scope.Scope> => | ||
| 92 | Effect.acquireRelease( | ||
| 93 | Effect.promise(() => startHttpApiTestServer(options)), | ||
| 94 | (server) => Effect.promise(() => server.close()).pipe(Effect.orDie), | ||
| 95 | ); | ||
| 96 | |||
| 97 | export const makeOpenApiTestServer = ( | ||
| 98 | options: HttpApiTestServerOptions, | ||
| 99 | ): Effect.Effect<RunningOpenApiTestServer, never, Scope.Scope> => | ||
| 100 | Effect.acquireRelease( | ||
| 101 | Effect.promise(() => startOpenApiTestServer(options)), | ||
| 102 | (server) => Effect.promise(() => server.close()).pipe(Effect.orDie), | ||
| 103 | ); | ||
| @@ -0,0 +1,15 @@ | |||
| 1 | { | ||
| 2 | "compilerOptions": { | ||
| 3 | "target": "ES2022", | ||
| 4 | "module": "ESNext", | ||
| 5 | "moduleResolution": "Bundler", | ||
| 6 | "strict": true, | ||
| 7 | "skipLibCheck": true, | ||
| 8 | "noEmit": true, | ||
| 9 | "lib": ["ES2022"], | ||
| 10 | "types": ["bun-types", "node"] | ||
| 11 | }, | ||
| 12 | "include": [ | ||
| 13 | "src/**/*.ts" | ||
| 14 | ] | ||
| 15 | } | ||
| @@ -154,8 +154,8 @@ const loadExecuteDescription = (runtime: ExecutorRuntime): Promise<string> => · 153 unmodified lines | |||
| 154 | Effect.gen(function* () { | 154 | Effect.gen(function* () { |
| 155 | const resolveExecutionEnvironment = yield* RuntimeExecutionResolverService; | 155 | const resolveExecutionEnvironment = yield* RuntimeExecutionResolverService; |
| 156 | const environment = yield* resolveExecutionEnvironment({ | 156 | const environment = yield* resolveExecutionEnvironment({ |
| 157 | workspaceId: runtime.localInstallation.workspaceId, | 157 | scopeId: runtime.localInstallation.scopeId, |
| 158 | accountId: runtime.localInstallation.accountId, | 158 | actorScopeId: runtime.localInstallation.actorScopeId, |
| 159 | executionId: ExecutionIdSchema.make("exec_mcp_help"), | 159 | executionId: ExecutionIdSchema.make("exec_mcp_help"), |
| 160 | }); | 160 | }); |
| 161 | 161 | ||
| @@ -260,7 +260,7 @@ const buildToolResult = (envelope: ExecutionEnvelope): ExecutorMcpToolResult => · 98 unmodified lines | |||
| 260 | 260 | ||
| 261 | const waitForInteractionProgress = async (input: { | 261 | const waitForInteractionProgress = async (input: { |
| 262 | runtime: ExecutorRuntime; | 262 | runtime: ExecutorRuntime; |
| 263 | workspaceId: string; | 263 | scopeId: string; |
| 264 | executionId: string; | 264 | executionId: string; |
| 265 | pendingInteractionId: string; | 265 | pendingInteractionId: string; |
| 266 | }): Promise<ExecutionEnvelope> => { | 266 | }): Promise<ExecutionEnvelope> => { |
| @@ -268,7 +268,7 @@ const waitForInteractionProgress = async (input: { · 1 unmodified line | |||
| 268 | const next = await runControlPlane( | 268 | const next = await runControlPlane( |
| 269 | input.runtime, | 269 | input.runtime, |
| 270 | getExecution({ | 270 | getExecution({ |
| 271 | workspaceId: input.workspaceId as never, | 271 | scopeId: input.scopeId as never, |
| 272 | executionId: input.executionId as never, | 272 | executionId: input.executionId as never, |
| 273 | }), | 273 | }), |
| 274 | ); | 274 | ); |
| @@ -286,8 +286,8 @@ const waitForInteractionProgress = async (input: { · 11 unmodified lines | |||
| 286 | 286 | ||
| 287 | const driveExecutionWithElicitation = async (input: { | 287 | const driveExecutionWithElicitation = async (input: { |
| 288 | runtime: ExecutorRuntime; | 288 | runtime: ExecutorRuntime; |
| 289 | workspaceId: string; | 289 | scopeId: string; |
| 290 | accountId: string; | 290 | actorScopeId: string; |
| 291 | server: McpServer; | 291 | server: McpServer; |
| 292 | envelope: ExecutionEnvelope; | 292 | envelope: ExecutionEnvelope; |
| 293 | }): Promise<ExecutionEnvelope> => { | 293 | }): Promise<ExecutionEnvelope> => { |
| @@ -317,13 +317,13 @@ const driveExecutionWithElicitation = async (input: { · 23 unmodified lines | |||
| 317 | current = await runControlPlane( | 317 | current = await runControlPlane( |
| 318 | input.runtime, | 318 | input.runtime, |
| 319 | resumeExecution({ | 319 | resumeExecution({ |
| 320 | workspaceId: input.workspaceId as never, | 320 | scopeId: input.scopeId as never, |
| 321 | executionId: current.execution.id as never, | 321 | executionId: current.execution.id as never, |
| 322 | payload: { | 322 | payload: { |
| 323 | responseJson: JSON.stringify(response), | 323 | responseJson: JSON.stringify(response), |
| 324 | interactionMode: interactionModeForServer(input.server), | 324 | interactionMode: interactionModeForServer(input.server), |
| 325 | }, | 325 | }, |
| 326 | resumedByAccountId: input.accountId as never, | 326 | resumedByScopeId: input.actorScopeId as never, |
| 327 | }), | 327 | }), |
| 328 | ); | 328 | ); |
| 329 | continue; | 329 | continue; |
| @@ -340,13 +340,13 @@ const driveExecutionWithElicitation = async (input: { · 10 unmodified lines | |||
| 340 | current = await runControlPlane( | 340 | current = await runControlPlane( |
| 341 | input.runtime, | 341 | input.runtime, |
| 342 | resumeExecution({ | 342 | resumeExecution({ |
| 343 | workspaceId: input.workspaceId as never, | 343 | scopeId: input.scopeId as never, |
| 344 | executionId: current.execution.id as never, | 344 | executionId: current.execution.id as never, |
| 345 | payload: { | 345 | payload: { |
| 346 | responseJson: JSON.stringify(response), | 346 | responseJson: JSON.stringify(response), |
| 347 | interactionMode: interactionModeForServer(input.server), | 347 | interactionMode: interactionModeForServer(input.server), |
| 348 | }, | 348 | }, |
| 349 | resumedByAccountId: input.accountId as never, | 349 | resumedByScopeId: input.actorScopeId as never, |
| 350 | }), | 350 | }), |
| 351 | ); | 351 | ); |
| 352 | continue; | 352 | continue; |
| @@ -354,7 +354,7 @@ const driveExecutionWithElicitation = async (input: { · 1 unmodified line | |||
| 354 | 354 | ||
| 355 | current = await waitForInteractionProgress({ | 355 | current = await waitForInteractionProgress({ |
| 356 | runtime: input.runtime, | 356 | runtime: input.runtime, |
| 357 | workspaceId: input.workspaceId, | 357 | scopeId: input.scopeId, |
| 358 | executionId: current.execution.id, | 358 | executionId: current.execution.id, |
| 359 | pendingInteractionId: pending.id, | 359 | pendingInteractionId: pending.id, |
| 360 | }); | 360 | }); |
| @@ -365,15 +365,15 @@ const driveExecutionWithElicitation = async (input: { · 4 unmodified lines | |||
| 365 | 365 | ||
| 366 | const driveExecutionWithoutElicitation = async (input: { | 366 | const driveExecutionWithoutElicitation = async (input: { |
| 367 | runtime: ExecutorRuntime; | 367 | runtime: ExecutorRuntime; |
| 368 | workspaceId: string; | 368 | scopeId: string; |
| 369 | accountId: string; | 369 | actorScopeId: string; |
| 370 | executionId: string; | 370 | executionId: string; |
| 371 | initialResponse?: ResumeResponseInput; | 371 | initialResponse?: ResumeResponseInput; |
| 372 | }): Promise<ExecutionEnvelope> => { | 372 | }): Promise<ExecutionEnvelope> => { |
| 373 | let current = await runControlPlane( | 373 | let current = await runControlPlane( |
| 374 | input.runtime, | 374 | input.runtime, |
| 375 | getExecution({ | 375 | getExecution({ |
| 376 | workspaceId: input.workspaceId as never, | 376 | scopeId: input.scopeId as never, |
| 377 | executionId: input.executionId as never, | 377 | executionId: input.executionId as never, |
| 378 | }), | 378 | }), |
| 379 | ); | 379 | ); |
| @@ -388,13 +388,13 @@ const driveExecutionWithoutElicitation = async (input: { · 8 unmodified lines | |||
| 388 | current = await runControlPlane( | 388 | current = await runControlPlane( |
| 389 | input.runtime, | 389 | input.runtime, |
| 390 | resumeExecution({ | 390 | resumeExecution({ |
| 391 | workspaceId: input.workspaceId as never, | 391 | scopeId: input.scopeId as never, |
| 392 | executionId: current.execution.id as never, | 392 | executionId: current.execution.id as never, |
| 393 | payload: { | 393 | payload: { |
| 394 | responseJson: JSON.stringify(response), | 394 | responseJson: JSON.stringify(response), |
| 395 | interactionMode: "detach", | 395 | interactionMode: "detach", |
| 396 | }, | 396 | }, |
| 397 | resumedByAccountId: input.accountId as never, | 397 | resumedByScopeId: input.actorScopeId as never, |
| 398 | }), | 398 | }), |
| 399 | ); | 399 | ); |
| 400 | response = undefined; | 400 | response = undefined; |
| @@ -416,8 +416,8 @@ const createExecutorMcpServer = async (config: { · 15 unmodified lines | |||
| 416 | }, | 416 | }, |
| 417 | ); | 417 | ); |
| 418 | 418 | ||
| 419 | const workspaceId = config.runtime.localInstallation.workspaceId; | 419 | const scopeId = config.runtime.localInstallation.scopeId; |
| 420 | const accountId = config.runtime.localInstallation.accountId; | 420 | const actorScopeId = config.runtime.localInstallation.actorScopeId; |
| 421 | 421 | ||
| 422 | const executeTool = server.registerTool( | 422 | const executeTool = server.registerTool( |
| 423 | "execute", | 423 | "execute", |
| @@ -429,20 +429,20 @@ const createExecutorMcpServer = async (config: { · 5 unmodified lines | |||
| 429 | let created = await runControlPlane( | 429 | let created = await runControlPlane( |
| 430 | config.runtime, | 430 | config.runtime, |
| 431 | createExecution({ | 431 | createExecution({ |
| 432 | workspaceId, | 432 | scopeId, |
| 433 | payload: { | 433 | payload: { |
| 434 | code, | 434 | code, |
| 435 | interactionMode: interactionModeForServer(server), | 435 | interactionMode: interactionModeForServer(server), |
| 436 | }, | 436 | }, |
| 437 | createdByAccountId: accountId, | 437 | createdByScopeId: actorScopeId, |
| 438 | }), | 438 | }), |
| 439 | ); | 439 | ); |
| 440 | 440 | ||
| 441 | if (supportsManagedElicitation(server)) { | 441 | if (supportsManagedElicitation(server)) { |
| 442 | created = await driveExecutionWithElicitation({ | 442 | created = await driveExecutionWithElicitation({ |
| 443 | runtime: config.runtime, | 443 | runtime: config.runtime, |
| 444 | workspaceId, | 444 | scopeId, |
| 445 | accountId, | 445 | actorScopeId, |
| 446 | server, | 446 | server, |
| 447 | envelope: created, | 447 | envelope: created, |
| 448 | }); | 448 | }); |
| @@ -469,8 +469,8 @@ const createExecutorMcpServer = async (config: { · 20 unmodified lines | |||
| 469 | ) => { | 469 | ) => { |
| 470 | const resumed = await driveExecutionWithoutElicitation({ | 470 | const resumed = await driveExecutionWithoutElicitation({ |
| 471 | runtime: config.runtime, | 471 | runtime: config.runtime, |
| 472 | workspaceId, | 472 | scopeId, |
| 473 | accountId, | 473 | actorScopeId, |
| 474 | executionId: input.resumePayload.executionId, | 474 | executionId: input.resumePayload.executionId, |
| 475 | initialResponse: input.response, | 475 | initialResponse: input.response, |
| 476 | }); | 476 | }); |
| @@ -35,8 +35,8 @@ const makeEnvelope = ( · 34 unmodified lines | |||
| 35 | ): ExecutionEnvelope => ({ | 35 | ): ExecutionEnvelope => ({ |
| 36 | execution: { | 36 | execution: { |
| 37 | id: "exec_123" as never, | 37 | id: "exec_123" as never, |
| 38 | workspaceId: "ws_123" as never, | 38 | scopeId: "ws_123" as never, |
| 39 | createdByAccountId: "acct_123" as never, | 39 | createdByScopeId: "acct_123" as never, |
| 40 | status: "waiting_for_interaction", | 40 | status: "waiting_for_interaction", |
| 41 | code: "return await tools.executor.sources.add({ endpoint: 'https://mcp.axiom.co/mcp' });", | 41 | code: "return await tools.executor.sources.add({ endpoint: 'https://mcp.axiom.co/mcp' });", |
| 42 | resultJson: null, | 42 | resultJson: null, |
| @@ -10,7 +10,7 @@ export type { · 9 unmodified lines | |||
| 10 | import { | 10 | import { |
| 11 | ExecutionIdSchema, | 11 | ExecutionIdSchema, |
| 12 | ExecutionEnvelopeSchema, | 12 | ExecutionEnvelopeSchema, |
| 13 | WorkspaceIdSchema, | 13 | ScopeIdSchema as WorkspaceIdSchema, |
| 14 | } from "@executor/platform-sdk/schema"; | 14 | } from "@executor/platform-sdk/schema"; |
| 15 | 15 | ||
| 16 | import { | 16 | import { |
| @@ -1,5 +1,5 @@ | |||
| 1 | import type { Executor } from "@executor/platform-sdk"; | 1 | import type { Executor } from "@executor/platform-sdk"; |
| 2 | import type { WorkspaceId } from "@executor/platform-sdk/schema"; | 2 | import type { ScopeId as WorkspaceId } from "@executor/platform-sdk/schema"; |
| 3 | import { | 3 | import { |
| 4 | ControlPlaneBadRequestError, | 4 | ControlPlaneBadRequestError, |
| 5 | ControlPlaneForbiddenError, | 5 | ControlPlaneForbiddenError, |
| @@ -23,13 +23,13 @@ export const resolveRequestedLocalWorkspace = ( · 17 unmodified lines | |||
| 23 | workspaceId: WorkspaceId, | 23 | workspaceId: WorkspaceId, |
| 24 | ) => | 24 | ) => |
| 25 | Effect.flatMap(ControlPlaneExecutor, (executor) => | 25 | Effect.flatMap(ControlPlaneExecutor, (executor) => |
| 26 | executor.workspaceId === workspaceId | 26 | executor.scopeId === workspaceId |
| 27 | ? Effect.succeed(executor) | 27 | ? Effect.succeed(executor) |
| 28 | : Effect.fail( | 28 | : Effect.fail( |
| 29 | new ControlPlaneForbiddenError({ | 29 | new ControlPlaneForbiddenError({ |
| 30 | operation, | 30 | operation, |
| 31 | message: "Requested workspace is not the active local workspace", | 31 | message: "Requested workspace is not the active local workspace", |
| 32 | details: `requestedWorkspaceId=${workspaceId} activeWorkspaceId=${executor.workspaceId}`, | 32 | details: `requestedWorkspaceId=${workspaceId} activeWorkspaceId=${executor.scopeId}`, |
| 33 | }), | 33 | }), |
| 34 | ), | 34 | ), |
| 35 | ); | 35 | ); |
| @@ -4,7 +4,7 @@ import { · 3 unmodified lines | |||
| 4 | SourceAuthSessionIdSchema, | 4 | SourceAuthSessionIdSchema, |
| 5 | SourceTransportSchema, | 5 | SourceTransportSchema, |
| 6 | StringMapSchema, | 6 | StringMapSchema, |
| 7 | WorkspaceIdSchema, | 7 | ScopeIdSchema as WorkspaceIdSchema, |
| 8 | } from "@executor/platform-sdk/schema"; | 8 | } from "@executor/platform-sdk/schema"; |
| 9 | import * as Schema from "effect/Schema"; | 9 | import * as Schema from "effect/Schema"; |
| 10 | 10 | ||
| @@ -3,7 +3,7 @@ import { · 2 unmodified lines | |||
| 3 | HttpServerRequest, | 3 | HttpServerRequest, |
| 4 | HttpServerResponse, | 4 | HttpServerResponse, |
| 5 | } from "@effect/platform"; | 5 | } from "@effect/platform"; |
| 6 | import type { WorkspaceId } from "@executor/platform-sdk/schema"; | 6 | import type { ScopeId as WorkspaceId } from "@executor/platform-sdk/schema"; |
| 7 | import * as Cause from "effect/Cause"; | 7 | import * as Cause from "effect/Cause"; |
| 8 | import * as Either from "effect/Either"; | 8 | import * as Either from "effect/Either"; |
| 9 | import * as Effect from "effect/Effect"; | 9 | import * as Effect from "effect/Effect"; |
| @@ -11,9 +11,9 @@ import { · 10 unmodified lines | |||
| 11 | ControlPlaneUnauthorizedError, | 11 | ControlPlaneUnauthorizedError, |
| 12 | } from "@executor/platform-sdk/errors"; | 12 | } from "@executor/platform-sdk/errors"; |
| 13 | import { | 13 | import { |
| 14 | LocalWorkspacePolicySchema, | 14 | LocalScopePolicySchema as LocalWorkspacePolicySchema, |
| 15 | PolicyIdSchema, | 15 | PolicyIdSchema, |
| 16 | WorkspaceIdSchema, | 16 | ScopeIdSchema as WorkspaceIdSchema, |
| 17 | } from "@executor/platform-sdk/schema"; | 17 | } from "@executor/platform-sdk/schema"; |
| 18 | import * as Schema from "effect/Schema"; | 18 | import * as Schema from "effect/Schema"; |
| 19 | 19 | ||
| @@ -5,13 +5,13 @@ import { · 4 unmodified lines | |||
| 5 | ConnectSourcePayloadSchema, | 5 | ConnectSourcePayloadSchema, |
| 6 | ConnectSourceResultSchema, | 6 | ConnectSourceResultSchema, |
| 7 | CreateSourcePayloadSchema, | 7 | CreateSourcePayloadSchema, |
| 8 | CreateWorkspaceOauthClientPayloadSchema, | 8 | CreateScopeOauthClientPayloadSchema as CreateWorkspaceOauthClientPayloadSchema, |
| 9 | CredentialOauthCompleteUrlParamsSchema, | 9 | CredentialOauthCompleteUrlParamsSchema, |
| 10 | CredentialPageUrlParamsSchema, | 10 | CredentialPageUrlParamsSchema, |
| 11 | CredentialSubmitPayloadSchema, | 11 | CredentialSubmitPayloadSchema, |
| 12 | DiscoverSourcePayloadSchema, | 12 | DiscoverSourcePayloadSchema, |
| 13 | UpdateSourcePayloadSchema, | 13 | UpdateSourcePayloadSchema, |
| 14 | WorkspaceOauthClientQuerySchema, | 14 | ScopeOauthClientQuerySchema as WorkspaceOauthClientQuerySchema, |
| 15 | } from "@executor/platform-sdk/contracts"; | 15 | } from "@executor/platform-sdk/contracts"; |
| 16 | import { | 16 | import { |
| 17 | ControlPlaneBadRequestError, | 17 | ControlPlaneBadRequestError, |
| @@ -29,9 +29,9 @@ import { · 11 unmodified lines | |||
| 29 | SourceInspectionSchema, | 29 | SourceInspectionSchema, |
| 30 | SourceInspectionToolDetailSchema, | 30 | SourceInspectionToolDetailSchema, |
| 31 | SourceSchema, | 31 | SourceSchema, |
| 32 | WorkspaceOauthClientIdSchema, | 32 | ScopeOauthClientIdSchema as WorkspaceOauthClientIdSchema, |
| 33 | WorkspaceOauthClientSchema, | 33 | ScopeOauthClientSchema as WorkspaceOauthClientSchema, |
| 34 | WorkspaceIdSchema, | 34 | ScopeIdSchema as WorkspaceIdSchema, |
| 35 | } from "@executor/platform-sdk/schema"; | 35 | } from "@executor/platform-sdk/schema"; |
| 36 | import * as Schema from "effect/Schema"; | 36 | import * as Schema from "effect/Schema"; |
| 37 | 37 | ||
| @@ -41,7 +41,7 @@ export type { · 3 unmodified lines | |||
| 41 | ConnectSourcePayload, | 41 | ConnectSourcePayload, |
| 42 | ConnectSourceResult, | 42 | ConnectSourceResult, |
| 43 | CreateSourcePayload, | 43 | CreateSourcePayload, |
| 44 | CreateWorkspaceOauthClientPayload, | 44 | CreateScopeOauthClientPayload as CreateWorkspaceOauthClientPayload, |
| 45 | DiscoverSourcePayload, | 45 | DiscoverSourcePayload, |
| 46 | UpdateSourcePayload, | 46 | UpdateSourcePayload, |
| 47 | } from "@executor/platform-sdk/contracts"; | 47 | } from "@executor/platform-sdk/contracts"; |
| @@ -6,8 +6,8 @@ import { · 5 unmodified lines | |||
| 6 | import type { | 6 | import type { |
| 7 | ExecutionInteraction, | 7 | ExecutionInteraction, |
| 8 | Source, | 8 | Source, |
| 9 | WorkspaceId, | 9 | ScopeId as WorkspaceId, |
| 10 | WorkspaceOauthClient, | 10 | ScopeOauthClient as WorkspaceOauthClient, |
| 11 | } from "@executor/platform-sdk/schema"; | 11 | } from "@executor/platform-sdk/schema"; |
| 12 | import type { | 12 | import type { |
| 13 | ExecutorMcpSourceInput, | 13 | ExecutorMcpSourceInput, |
| @@ -18,7 +18,7 @@ import * as Effect from "effect/Effect"; · 4 unmodified lines | |||
| 18 | import { | 18 | import { |
| 19 | sourceAdapterRequiresInteractiveConnect, | 19 | sourceAdapterRequiresInteractiveConnect, |
| 20 | } from "@executor/platform-sdk/runtime"; | 20 | } from "@executor/platform-sdk/runtime"; |
| 21 | import { WorkspaceOauthClientIdSchema } from "@executor/platform-sdk/schema"; | 21 | import { ScopeOauthClientIdSchema as WorkspaceOauthClientIdSchema } from "@executor/platform-sdk/schema"; |
| 22 | 22 | ||
| 23 | import { | 23 | import { |
| 24 | ControlPlaneBadRequestError, | 24 | ControlPlaneBadRequestError, |
| @@ -130,8 +130,8 @@ const toExecutorSourceInput = ( · 105 unmodified lines | |||
| 130 | version: payload.version, | 130 | version: payload.version, |
| 131 | discoveryUrl: payload.discoveryUrl, | 131 | discoveryUrl: payload.discoveryUrl, |
| 132 | scopes: payload.scopes, | 132 | scopes: payload.scopes, |
| 133 | workspaceOauthClientId: toWorkspaceOauthClientId( | 133 | scopeOauthClientId: toWorkspaceOauthClientId( |
| 134 | payload.workspaceOauthClientId, | 134 | payload.scopeOauthClientId, |
| 135 | ), | 135 | ), |
| 136 | oauthClient: payload.oauthClient, | 136 | oauthClient: payload.oauthClient, |
| 137 | name: payload.name, | 137 | name: payload.name, |
| @@ -1137,7 +1137,7 @@ export const ExecutorSourcesLive = HttpApiBuilder.group( · 999 unmodified lines | |||
| 1137 | Effect.flatMap((executor) => | 1137 | Effect.flatMap((executor) => |
| 1138 | Effect.gen(function* () { | 1138 | Effect.gen(function* () { |
| 1139 | const completed = yield* executor.effect.oauth.completeProviderCallback({ | 1139 | const completed = yield* executor.effect.oauth.completeProviderCallback({ |
| 1140 | workspaceId: path.workspaceId, | 1140 | scopeId: path.workspaceId, |
| 1141 | state: urlParams.state, | 1141 | state: urlParams.state, |
| 1142 | code: urlParams.code, | 1142 | code: urlParams.code, |
| 1143 | error: urlParams.error, | 1143 | error: urlParams.error, |
| @@ -1,9 +1,9 @@ | |||
| 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 type { Executor } from "@executor/platform-sdk"; |
| 3 | import { | 3 | import { |
| 4 | type AccountId, | 4 | type ScopeId as AccountId, |
| 5 | LocalInstallationSchema, | 5 | LocalInstallationSchema, |
| 6 | LocalWorkspacePolicySchema, | 6 | LocalScopePolicySchema, |
| 7 | SourceDiscoveryResultSchema, | 7 | SourceDiscoveryResultSchema, |
| 8 | SourceIdSchema, | 8 | SourceIdSchema, |
| 9 | SourceInspectionDiscoverPayloadSchema, | 9 | SourceInspectionDiscoverPayloadSchema, |
| @@ -11,8 +11,8 @@ import { · 1 unmodified line | |||
| 11 | SourceInspectionSchema, | 11 | SourceInspectionSchema, |
| 12 | SourceInspectionToolDetailSchema, | 12 | SourceInspectionToolDetailSchema, |
| 13 | SourceSchema, | 13 | SourceSchema, |
| 14 | type WorkspaceId, | 14 | type ScopeId as WorkspaceId, |
| 15 | WorkspaceOauthClientSchema, | 15 | ScopeOauthClientSchema, |
| 16 | } from "@executor/platform-sdk/schema"; | 16 | } from "@executor/platform-sdk/schema"; |
| 17 | import * as Effect from "effect/Effect"; | 17 | import * as Effect from "effect/Effect"; |
| 18 | import * as Layer from "effect/Layer"; | 18 | import * as Layer from "effect/Layer"; |
| @@ -25,25 +25,25 @@ import { · 6 unmodified lines | |||
| 25 | SecretMaterialStorerService, | 25 | SecretMaterialStorerService, |
| 26 | SecretMaterialUpdaterService, | 26 | SecretMaterialUpdaterService, |
| 27 | type ExecutorStateStoreShape, | 27 | type ExecutorStateStoreShape, |
| 28 | type WorkspaceInternalToolContext, | 28 | type ScopeInternalToolContext as WorkspaceInternalToolContext, |
| 29 | RuntimeSourceAuthService, | 29 | RuntimeSourceAuthService, |
| 30 | RuntimeSourceCatalogSyncService, | 30 | RuntimeSourceCatalogSyncService, |
| 31 | RuntimeSourceStore, | 31 | RuntimeSourceStore, |
| 32 | RuntimeSourceStoreService, | 32 | RuntimeSourceStoreService, |
| 33 | } from "@executor/platform-sdk/runtime"; | 33 | } from "@executor/platform-sdk/runtime"; |
| 34 | import { | 34 | import { |
| 35 | type RuntimeLocalWorkspaceState, | 35 | type RuntimeLocalScopeState, |
| 36 | provideOptionalRuntimeLocalWorkspace, | 36 | provideOptionalRuntimeLocalScope, |
| 37 | } from "../../../sdk/src/runtime/workspace/runtime-context"; | 37 | } from "../../../sdk/src/runtime/scope/runtime-context"; |
| 38 | import { | 38 | import { |
| 39 | SourceArtifactStore, | 39 | SourceArtifactStore, |
| 40 | type SourceArtifactStoreShape, | 40 | type SourceArtifactStoreShape, |
| 41 | WorkspaceConfigStore, | 41 | ScopeConfigStore, |
| 42 | type WorkspaceConfigStoreShape, | 42 | type ScopeConfigStoreShape, |
| 43 | WorkspaceStateStore, | 43 | ScopeStateStore, |
| 44 | type WorkspaceStateStoreShape, | 44 | type ScopeStateStoreShape, |
| 45 | makeWorkspaceStorageLayer, | 45 | makeScopeStorageLayer, |
| 46 | } from "../../../sdk/src/runtime/workspace/storage"; | 46 | } from "../../../sdk/src/runtime/scope/storage"; |
| 47 | import { | 47 | import { |
| 48 | CreateSecretPayloadSchema, | 48 | CreateSecretPayloadSchema, |
| 49 | CreateSecretResultSchema, | 49 | CreateSecretResultSchema, |
| @@ -81,9 +81,9 @@ import { · 31 unmodified lines | |||
| 81 | UpdatePolicyPayloadSchema, | 81 | UpdatePolicyPayloadSchema, |
| 82 | } from "@executor/platform-sdk/contracts"; | 82 | } from "@executor/platform-sdk/contracts"; |
| 83 | import { | 83 | import { |
| 84 | CreateWorkspaceOauthClientPayloadSchema, | 84 | CreateScopeOauthClientPayloadSchema, |
| 85 | DiscoverSourcePayloadSchema, | 85 | DiscoverSourcePayloadSchema, |
| 86 | type CreateWorkspaceOauthClientPayload, | 86 | type CreateScopeOauthClientPayload as CreateWorkspaceOauthClientPayload, |
| 87 | UpdateSourcePayloadSchema, | 87 | UpdateSourcePayloadSchema, |
| 88 | } from "@executor/platform-sdk/contracts"; | 88 | } from "@executor/platform-sdk/contracts"; |
| 89 | 89 | ||
| @@ -145,7 +145,7 @@ const inspectDiscoverInputSchema = Schema.standardSchemaV1( · 55 unmodified lines | |||
| 145 | }), | 145 | }), |
| 146 | ); | 146 | ); |
| 147 | const listPoliciesOutputSchema = Schema.standardSchemaV1( | 147 | const listPoliciesOutputSchema = Schema.standardSchemaV1( |
| 148 | Schema.Array(LocalWorkspacePolicySchema), | 148 | Schema.Array(LocalScopePolicySchema), |
| 149 | ); | 149 | ); |
| 150 | const policyIdInputSchema = Schema.standardSchemaV1( | 150 | const policyIdInputSchema = Schema.standardSchemaV1( |
| 151 | Schema.Struct({ | 151 | Schema.Struct({ |
| @@ -167,10 +167,10 @@ const workspaceOauthClientListInputSchema = Schema.standardSchemaV1( · 15 unmodified lines | |||
| 167 | }), | 167 | }), |
| 168 | ); | 168 | ); |
| 169 | const workspaceOauthClientListOutputSchema = Schema.standardSchemaV1( | 169 | const workspaceOauthClientListOutputSchema = Schema.standardSchemaV1( |
| 170 | Schema.Array(WorkspaceOauthClientSchema), | 170 | Schema.Array(ScopeOauthClientSchema), |
| 171 | ); | 171 | ); |
| 172 | const createWorkspaceOauthClientInputSchema = Schema.standardSchemaV1( | 172 | const createWorkspaceOauthClientInputSchema = Schema.standardSchemaV1( |
| 173 | CreateWorkspaceOauthClientPayloadSchema, | 173 | CreateScopeOauthClientPayloadSchema, |
| 174 | ); | 174 | ); |
| 175 | const removeWorkspaceOauthClientInputSchema = Schema.standardSchemaV1( | 175 | const removeWorkspaceOauthClientInputSchema = Schema.standardSchemaV1( |
| 176 | Schema.Struct({ | 176 | Schema.Struct({ |
| @@ -195,8 +195,8 @@ const sourceInspectionDiscoverOutputSchema = Schema.standardSchemaV1( · 18 unmodified lines | |||
| 195 | const sourceDiscoveryOutputSchema = Schema.standardSchemaV1( | 195 | const sourceDiscoveryOutputSchema = Schema.standardSchemaV1( |
| 196 | SourceDiscoveryResultSchema, | 196 | SourceDiscoveryResultSchema, |
| 197 | ); | 197 | ); |
| 198 | const localWorkspacePolicyOutputSchema = Schema.standardSchemaV1( | 198 | const localScopePolicyOutputSchema = Schema.standardSchemaV1( |
| 199 | LocalWorkspacePolicySchema, | 199 | LocalScopePolicySchema, |
| 200 | ); | 200 | ); |
| 201 | 201 | ||
| 202 | const makeRuntimeLayer = (input: { | 202 | const makeRuntimeLayer = (input: { |
| @@ -205,8 +205,8 @@ const makeRuntimeLayer = (input: { · 2 unmodified lines | |||
| 205 | sourceCatalogSyncService: Effect.Effect.Success< | 205 | sourceCatalogSyncService: Effect.Effect.Success< |
| 206 | typeof RuntimeSourceCatalogSyncService | 206 | typeof RuntimeSourceCatalogSyncService |
| 207 | >; | 207 | >; |
| 208 | workspaceConfigStore: WorkspaceConfigStoreShape; | 208 | scopeConfigStore: ScopeConfigStoreShape; |
| 209 | workspaceStateStore: WorkspaceStateStoreShape; | 209 | scopeStateStore: ScopeStateStoreShape; |
| 210 | sourceArtifactStore: SourceArtifactStoreShape; | 210 | sourceArtifactStore: SourceArtifactStoreShape; |
| 211 | instanceConfigResolver: WorkspaceInternalToolContext["instanceConfigResolver"]; | 211 | instanceConfigResolver: WorkspaceInternalToolContext["instanceConfigResolver"]; |
| 212 | storeSecretMaterial: WorkspaceInternalToolContext["storeSecretMaterial"]; | 212 | storeSecretMaterial: WorkspaceInternalToolContext["storeSecretMaterial"]; |
| @@ -224,9 +224,9 @@ const makeRuntimeLayer = (input: { · 11 unmodified lines | |||
| 224 | Layer.succeed(SecretMaterialStorerService, input.storeSecretMaterial), | 224 | Layer.succeed(SecretMaterialStorerService, input.storeSecretMaterial), |
| 225 | Layer.succeed(SecretMaterialDeleterService, input.deleteSecretMaterial), | 225 | Layer.succeed(SecretMaterialDeleterService, input.deleteSecretMaterial), |
| 226 | Layer.succeed(SecretMaterialUpdaterService, input.updateSecretMaterial), | 226 | Layer.succeed(SecretMaterialUpdaterService, input.updateSecretMaterial), |
| 227 | makeWorkspaceStorageLayer({ | 227 | makeScopeStorageLayer({ |
| 228 | workspaceConfigStore: input.workspaceConfigStore, | 228 | scopeConfigStore: input.scopeConfigStore, |
| 229 | workspaceStateStore: input.workspaceStateStore, | 229 | scopeStateStore: input.scopeStateStore, |
| 230 | sourceArtifactStore: input.sourceArtifactStore, | 230 | sourceArtifactStore: input.sourceArtifactStore, |
| 231 | }), | 231 | }), |
| 232 | ); | 232 | ); |
| @@ -241,34 +241,34 @@ const runRuntimeEffect = <A, E, R>(input: { · 8 unmodified lines | |||
| 241 | | SecretMaterialStorerService | 241 | | SecretMaterialStorerService |
| 242 | | SecretMaterialDeleterService | 242 | | SecretMaterialDeleterService |
| 243 | | SecretMaterialUpdaterService | 243 | | SecretMaterialUpdaterService |
| 244 | | WorkspaceConfigStore | 244 | | ScopeConfigStore |
| 245 | | WorkspaceStateStore | 245 | | ScopeStateStore |
| 246 | | SourceArtifactStore, | 246 | | SourceArtifactStore, |
| 247 | never, | 247 | never, |
| 248 | never | 248 | never |
| 249 | >; | 249 | >; |
| 250 | runtimeLocalWorkspace: RuntimeLocalWorkspaceState | null; | 250 | runtimeLocalScope: RuntimeLocalScopeState | null; |
| 251 | }) => | 251 | }) => |
| 252 | Effect.runPromise( | 252 | Effect.runPromise( |
| 253 | provideOptionalRuntimeLocalWorkspace( | 253 | provideOptionalRuntimeLocalScope( |
| 254 | input.effect.pipe(Effect.provide(input.runtimeLayer)), | 254 | input.effect.pipe(Effect.provide(input.runtimeLayer)), |
| 255 | input.runtimeLocalWorkspace, | 255 | input.runtimeLocalScope, |
| 256 | ) as Effect.Effect<A, E, never>, | 256 | ) as Effect.Effect<A, E, never>, |
| 257 | ); | 257 | ); |
| 258 | 258 | ||
| 259 | const runWorkspaceStorageEffect = <A, E, R>(input: { | 259 | const runScopeStorageEffect = <A, E, R>(input: { |
| 260 | effect: Effect.Effect<A, E, R>; | 260 | effect: Effect.Effect<A, E, R>; |
| 261 | workspaceStorageLayer: Layer.Layer< | 261 | scopeStorageLayer: Layer.Layer< |
| 262 | WorkspaceConfigStore | WorkspaceStateStore | SourceArtifactStore, | 262 | ScopeConfigStore | ScopeStateStore | SourceArtifactStore, |
| 263 | never, | 263 | never, |
| 264 | never | 264 | never |
| 265 | >; | 265 | >; |
| 266 | runtimeLocalWorkspace: RuntimeLocalWorkspaceState | null; | 266 | runtimeLocalScope: RuntimeLocalScopeState | null; |
| 267 | }) => | 267 | }) => |
| 268 | Effect.runPromise( | 268 | Effect.runPromise( |
| 269 | provideOptionalRuntimeLocalWorkspace( | 269 | provideOptionalRuntimeLocalScope( |
| 270 | input.effect.pipe(Effect.provide(input.workspaceStorageLayer)), | 270 | input.effect.pipe(Effect.provide(input.scopeStorageLayer)), |
| 271 | input.runtimeLocalWorkspace, | 271 | input.runtimeLocalScope, |
| 272 | ) as Effect.Effect<A, E, never>, | 272 | ) as Effect.Effect<A, E, never>, |
| 273 | ); | 273 | ); |
| 274 | 274 | ||
| @@ -279,17 +279,17 @@ export const createWorkspaceExecutorAdminToolMap = ( · 4 unmodified lines | |||
| 279 | executorStateStore: input.executorStateStore, | 279 | executorStateStore: input.executorStateStore, |
| 280 | sourceStore: input.sourceStore, | 280 | sourceStore: input.sourceStore, |
| 281 | sourceCatalogSyncService: input.sourceCatalogSyncService, | 281 | sourceCatalogSyncService: input.sourceCatalogSyncService, |
| 282 | workspaceConfigStore: input.workspaceConfigStore, | 282 | scopeConfigStore: input.scopeConfigStore, |
| 283 | workspaceStateStore: input.workspaceStateStore, | 283 | scopeStateStore: input.scopeStateStore, |
| 284 | sourceArtifactStore: input.sourceArtifactStore, | 284 | sourceArtifactStore: input.sourceArtifactStore, |
| 285 | instanceConfigResolver: input.instanceConfigResolver, | 285 | instanceConfigResolver: input.instanceConfigResolver, |
| 286 | storeSecretMaterial: input.storeSecretMaterial, | 286 | storeSecretMaterial: input.storeSecretMaterial, |
| 287 | deleteSecretMaterial: input.deleteSecretMaterial, | 287 | deleteSecretMaterial: input.deleteSecretMaterial, |
| 288 | updateSecretMaterial: input.updateSecretMaterial, | 288 | updateSecretMaterial: input.updateSecretMaterial, |
| 289 | }); | 289 | }); |
| 290 | const workspaceStorageLayer = makeWorkspaceStorageLayer({ | 290 | const scopeStorageLayer = makeScopeStorageLayer({ |
| 291 | workspaceConfigStore: input.workspaceConfigStore, | 291 | scopeConfigStore: input.scopeConfigStore, |
| 292 | workspaceStateStore: input.workspaceStateStore, | 292 | scopeStateStore: input.scopeStateStore, |
| 293 | sourceArtifactStore: input.sourceArtifactStore, | 293 | sourceArtifactStore: input.sourceArtifactStore, |
| 294 | }); | 294 | }); |
| 295 | 295 | ||
| @@ -306,8 +306,8 @@ export const createWorkspaceExecutorAdminToolMap = ( · 10 unmodified lines | |||
| 306 | inputSchema: emptyInputSchema, | 306 | inputSchema: emptyInputSchema, |
| 307 | outputSchema: localInstallationOutputSchema, | 307 | outputSchema: localInstallationOutputSchema, |
| 308 | execute: async () => ({ | 308 | execute: async () => ({ |
| 309 | workspaceId: input.workspaceId, | 309 | scopeId: input.scopeId, |
| 310 | accountId: input.accountId, | 310 | actorScopeId: input.actorScopeId, |
| 311 | }), | 311 | }), |
| 312 | }, | 312 | }, |
| 313 | metadata, | 313 | metadata, |
| @@ -332,7 +332,7 @@ export const createWorkspaceExecutorAdminToolMap = ( · 18 unmodified lines | |||
| 332 | runRuntimeEffect({ | 332 | runRuntimeEffect({ |
| 333 | effect: listLocalSecrets(), | 333 | effect: listLocalSecrets(), |
| 334 | runtimeLayer, | 334 | runtimeLayer, |
| 335 | runtimeLocalWorkspace: input.runtimeLocalWorkspace, | 335 | runtimeLocalScope: input.runtimeLocalScope, |
| 336 | }), | 336 | }), |
| 337 | }, | 337 | }, |
| 338 | metadata, | 338 | metadata, |
| @@ -347,7 +347,7 @@ export const createWorkspaceExecutorAdminToolMap = ( · 8 unmodified lines | |||
| 347 | runRuntimeEffect({ | 347 | runRuntimeEffect({ |
| 348 | effect: createLocalSecret(payload), | 348 | effect: createLocalSecret(payload), |
| 349 | runtimeLayer, | 349 | runtimeLayer, |
| 350 | runtimeLocalWorkspace: input.runtimeLocalWorkspace, | 350 | runtimeLocalScope: input.runtimeLocalScope, |
| 351 | }), | 351 | }), |
| 352 | }, | 352 | }, |
| 353 | metadata, | 353 | metadata, |
| @@ -365,7 +365,7 @@ export const createWorkspaceExecutorAdminToolMap = ( · 11 unmodified lines | |||
| 365 | runRuntimeEffect({ | 365 | runRuntimeEffect({ |
| 366 | effect: updateLocalSecret(payload), | 366 | effect: updateLocalSecret(payload), |
| 367 | runtimeLayer, | 367 | runtimeLayer, |
| 368 | runtimeLocalWorkspace: input.runtimeLocalWorkspace, | 368 | runtimeLocalScope: input.runtimeLocalScope, |
| 369 | }), | 369 | }), |
| 370 | }, | 370 | }, |
| 371 | metadata, | 371 | metadata, |
| @@ -379,7 +379,7 @@ export const createWorkspaceExecutorAdminToolMap = ( · 7 unmodified lines | |||
| 379 | runRuntimeEffect({ | 379 | runRuntimeEffect({ |
| 380 | effect: deleteLocalSecret(secretId), | 380 | effect: deleteLocalSecret(secretId), |
| 381 | runtimeLayer, | 381 | runtimeLayer, |
| 382 | runtimeLocalWorkspace: input.runtimeLocalWorkspace, | 382 | runtimeLocalScope: input.runtimeLocalScope, |
| 383 | }), | 383 | }), |
| 384 | }, | 384 | }, |
| 385 | metadata, | 385 | metadata, |
| @@ -408,11 +408,11 @@ export const createWorkspaceExecutorAdminToolMap = ( · 22 unmodified lines | |||
| 408 | execute: () => | 408 | execute: () => |
| 409 | runRuntimeEffect({ | 409 | runRuntimeEffect({ |
| 410 | effect: listSources({ | 410 | effect: listSources({ |
| 411 | workspaceId: input.workspaceId, | 411 | scopeId: input.scopeId, |
| 412 | accountId: input.accountId as never, | 412 | actorScopeId: input.actorScopeId as never, |
| 413 | }), | 413 | }), |
| 414 | runtimeLayer, | 414 | runtimeLayer, |
| 415 | runtimeLocalWorkspace: input.runtimeLocalWorkspace, | 415 | runtimeLocalScope: input.runtimeLocalScope, |
| 416 | }), | 416 | }), |
| 417 | }, | 417 | }, |
| 418 | metadata, | 418 | metadata, |
| @@ -425,12 +425,12 @@ export const createWorkspaceExecutorAdminToolMap = ( · 6 unmodified lines | |||
| 425 | execute: ({ sourceId }: { sourceId: string }) => | 425 | execute: ({ sourceId }: { sourceId: string }) => |
| 426 | runRuntimeEffect({ | 426 | runRuntimeEffect({ |
| 427 | effect: getSource({ | 427 | effect: getSource({ |
| 428 | workspaceId: input.workspaceId, | 428 | scopeId: input.scopeId, |
| 429 | sourceId: sourceId as never, | 429 | sourceId: sourceId as never, |
| 430 | accountId: input.accountId as never, | 430 | actorScopeId: input.actorScopeId as never, |
| 431 | }), | 431 | }), |
| 432 | runtimeLayer, | 432 | runtimeLayer, |
| 433 | runtimeLocalWorkspace: input.runtimeLocalWorkspace, | 433 | runtimeLocalScope: input.runtimeLocalScope, |
| 434 | }), | 434 | }), |
| 435 | }, | 435 | }, |
| 436 | metadata, | 436 | metadata, |
| @@ -446,13 +446,13 @@ export const createWorkspaceExecutorAdminToolMap = ( · 9 unmodified lines | |||
| 446 | }) => | 446 | }) => |
| 447 | runRuntimeEffect({ | 447 | runRuntimeEffect({ |
| 448 | effect: updateSource({ | 448 | effect: updateSource({ |
| 449 | workspaceId: input.workspaceId, | 449 | scopeId: input.scopeId, |
| 450 | sourceId: payload.sourceId as never, | 450 | sourceId: payload.sourceId as never, |
| 451 | accountId: input.accountId as never, | 451 | actorScopeId: input.actorScopeId as never, |
| 452 | payload: payload.payload as never, | 452 | payload: payload.payload as never, |
| 453 | }), | 453 | }), |
| 454 | runtimeLayer, | 454 | runtimeLayer, |
| 455 | runtimeLocalWorkspace: input.runtimeLocalWorkspace, | 455 | runtimeLocalScope: input.runtimeLocalScope, |
| 456 | }), | 456 | }), |
| 457 | }, | 457 | }, |
| 458 | metadata, | 458 | metadata, |
| @@ -465,11 +465,11 @@ export const createWorkspaceExecutorAdminToolMap = ( · 6 unmodified lines | |||
| 465 | execute: ({ sourceId }: { sourceId: string }) => | 465 | execute: ({ sourceId }: { sourceId: string }) => |
| 466 | runRuntimeEffect({ | 466 | runRuntimeEffect({ |
| 467 | effect: removeSource({ | 467 | effect: removeSource({ |
| 468 | workspaceId: input.workspaceId, | 468 | scopeId: input.scopeId, |
| 469 | sourceId: sourceId as never, | 469 | sourceId: sourceId as never, |
| 470 | }), | 470 | }), |
| 471 | runtimeLayer, | 471 | runtimeLayer, |
| 472 | runtimeLocalWorkspace: input.runtimeLocalWorkspace, | 472 | runtimeLocalScope: input.runtimeLocalScope, |
| 473 | }), | 473 | }), |
| 474 | }, | 474 | }, |
| 475 | metadata, | 475 | metadata, |
| @@ -482,11 +482,11 @@ export const createWorkspaceExecutorAdminToolMap = ( · 6 unmodified lines | |||
| 482 | execute: ({ sourceId }: { sourceId: string }) => | 482 | execute: ({ sourceId }: { sourceId: string }) => |
| 483 | runRuntimeEffect({ | 483 | runRuntimeEffect({ |
| 484 | effect: getSourceInspection({ | 484 | effect: getSourceInspection({ |
| 485 | workspaceId: input.workspaceId, | 485 | scopeId: input.scopeId, |
| 486 | sourceId: sourceId as never, | 486 | sourceId: sourceId as never, |
| 487 | }), | 487 | }), |
| 488 | runtimeLayer, | 488 | runtimeLayer, |
| 489 | runtimeLocalWorkspace: input.runtimeLocalWorkspace, | 489 | runtimeLocalScope: input.runtimeLocalScope, |
| 490 | }), | 490 | }), |
| 491 | }, | 491 | }, |
| 492 | metadata, | 492 | metadata, |
| @@ -505,12 +505,12 @@ export const createWorkspaceExecutorAdminToolMap = ( · 12 unmodified lines | |||
| 505 | }) => | 505 | }) => |
| 506 | runRuntimeEffect({ | 506 | runRuntimeEffect({ |
| 507 | effect: getSourceInspectionToolDetail({ | 507 | effect: getSourceInspectionToolDetail({ |
| 508 | workspaceId: input.workspaceId, | 508 | scopeId: input.scopeId, |
| 509 | sourceId: sourceId as never, | 509 | sourceId: sourceId as never, |
| 510 | toolPath, | 510 | toolPath, |
| 511 | }), | 511 | }), |
| 512 | runtimeLayer, | 512 | runtimeLayer, |
| 513 | runtimeLocalWorkspace: input.runtimeLocalWorkspace, | 513 | runtimeLocalScope: input.runtimeLocalScope, |
| 514 | }), | 514 | }), |
| 515 | }, | 515 | }, |
| 516 | metadata, | 516 | metadata, |
| @@ -529,12 +529,12 @@ export const createWorkspaceExecutorAdminToolMap = ( · 12 unmodified lines | |||
| 529 | }) => | 529 | }) => |
| 530 | runRuntimeEffect({ | 530 | runRuntimeEffect({ |
| 531 | effect: discoverSourceInspectionTools({ | 531 | effect: discoverSourceInspectionTools({ |
| 532 | workspaceId: input.workspaceId, | 532 | scopeId: input.scopeId, |
| 533 | sourceId: sourceId as never, | 533 | sourceId: sourceId as never, |
| 534 | payload: payload as never, | 534 | payload: payload as never, |
| 535 | }), | 535 | }), |
| 536 | runtimeLayer, | 536 | runtimeLayer, |
| 537 | runtimeLocalWorkspace: input.runtimeLocalWorkspace, | 537 | runtimeLocalScope: input.runtimeLocalScope, |
| 538 | }), | 538 | }), |
| 539 | }, | 539 | }, |
| 540 | metadata, | 540 | metadata, |
| @@ -545,13 +545,13 @@ export const createWorkspaceExecutorAdminToolMap = ( · 4 unmodified lines | |||
| 545 | inputSchema: workspaceOauthClientListInputSchema, | 545 | inputSchema: workspaceOauthClientListInputSchema, |
| 546 | outputSchema: workspaceOauthClientListOutputSchema, | 546 | outputSchema: workspaceOauthClientListOutputSchema, |
| 547 | execute: ({ providerKey }: { providerKey: string }) => | 547 | execute: ({ providerKey }: { providerKey: string }) => |
| 548 | runWorkspaceStorageEffect({ | 548 | runScopeStorageEffect({ |
| 549 | effect: input.sourceAuthService.listWorkspaceOauthClients({ | 549 | effect: input.sourceAuthService.listScopeOauthClients({ |
| 550 | workspaceId: input.workspaceId, | 550 | scopeId: input.scopeId, |
| 551 | providerKey, | 551 | providerKey, |
| 552 | }), | 552 | }), |
| 553 | workspaceStorageLayer, | 553 | scopeStorageLayer, |
| 554 | runtimeLocalWorkspace: input.runtimeLocalWorkspace, | 554 | runtimeLocalScope: input.runtimeLocalScope, |
| 555 | }), | 555 | }), |
| 556 | }, | 556 | }, |
| 557 | metadata, | 557 | metadata, |
| @@ -561,17 +561,17 @@ export const createWorkspaceExecutorAdminToolMap = ( · 3 unmodified lines | |||
| 561 | description: | 561 | description: |
| 562 | "Create a workspace OAuth client used for shared provider auth flows.", | 562 | "Create a workspace OAuth client used for shared provider auth flows.", |
| 563 | inputSchema: createWorkspaceOauthClientInputSchema, | 563 | inputSchema: createWorkspaceOauthClientInputSchema, |
| 564 | outputSchema: Schema.standardSchemaV1(WorkspaceOauthClientSchema), | 564 | outputSchema: Schema.standardSchemaV1(ScopeOauthClientSchema), |
| 565 | execute: (payload: CreateWorkspaceOauthClientPayload) => | 565 | execute: (payload: CreateWorkspaceOauthClientPayload) => |
| 566 | runWorkspaceStorageEffect({ | 566 | runScopeStorageEffect({ |
| 567 | effect: input.sourceAuthService.createWorkspaceOauthClient({ | 567 | effect: input.sourceAuthService.createScopeOauthClient({ |
| 568 | workspaceId: input.workspaceId, | 568 | scopeId: input.scopeId, |
| 569 | providerKey: payload.providerKey, | 569 | providerKey: payload.providerKey, |
| 570 | label: payload.label, | 570 | label: payload.label, |
| 571 | oauthClient: payload.oauthClient, | 571 | oauthClient: payload.oauthClient, |
| 572 | }), | 572 | }), |
| 573 | workspaceStorageLayer, | 573 | scopeStorageLayer, |
| 574 | runtimeLocalWorkspace: input.runtimeLocalWorkspace, | 574 | runtimeLocalScope: input.runtimeLocalScope, |
| 575 | }), | 575 | }), |
| 576 | }, | 576 | }, |
| 577 | metadata, | 577 | metadata, |
| @@ -582,15 +582,15 @@ export const createWorkspaceExecutorAdminToolMap = ( · 4 unmodified lines | |||
| 582 | inputSchema: removeWorkspaceOauthClientInputSchema, | 582 | inputSchema: removeWorkspaceOauthClientInputSchema, |
| 583 | outputSchema: removeResultSchema, | 583 | outputSchema: removeResultSchema, |
| 584 | execute: ({ oauthClientId }: { oauthClientId: string }) => | 584 | execute: ({ oauthClientId }: { oauthClientId: string }) => |
| 585 | runWorkspaceStorageEffect({ | 585 | runScopeStorageEffect({ |
| 586 | effect: input.sourceAuthService | 586 | effect: input.sourceAuthService |
| 587 | .removeWorkspaceOauthClient({ | 587 | .removeScopeOauthClient({ |
| 588 | workspaceId: input.workspaceId, | 588 | scopeId: input.scopeId, |
| 589 | oauthClientId: oauthClientId as never, | 589 | oauthClientId: oauthClientId as never, |
| 590 | }) | 590 | }) |
| 591 | .pipe(Effect.map((removed) => ({ removed }))), | 591 | .pipe(Effect.map((removed) => ({ removed }))), |
| 592 | workspaceStorageLayer, | 592 | scopeStorageLayer, |
| 593 | runtimeLocalWorkspace: input.runtimeLocalWorkspace, | 593 | runtimeLocalScope: input.runtimeLocalScope, |
| 594 | }), | 594 | }), |
| 595 | }, | 595 | }, |
| 596 | metadata, | 596 | metadata, |
| @@ -602,15 +602,15 @@ export const createWorkspaceExecutorAdminToolMap = ( · 5 unmodified lines | |||
| 602 | inputSchema: removeProviderGrantInputSchema, | 602 | inputSchema: removeProviderGrantInputSchema, |
| 603 | outputSchema: removeResultSchema, | 603 | outputSchema: removeResultSchema, |
| 604 | execute: ({ grantId }: { grantId: string }) => | 604 | execute: ({ grantId }: { grantId: string }) => |
| 605 | runWorkspaceStorageEffect({ | 605 | runScopeStorageEffect({ |
| 606 | effect: input.sourceAuthService | 606 | effect: input.sourceAuthService |
| 607 | .removeProviderAuthGrant({ | 607 | .removeProviderAuthGrant({ |
| 608 | workspaceId: input.workspaceId, | 608 | scopeId: input.scopeId, |
| 609 | grantId: grantId as never, | 609 | grantId: grantId as never, |
| 610 | }) | 610 | }) |
| 611 | .pipe(Effect.map((removed) => ({ removed }))), | 611 | .pipe(Effect.map((removed) => ({ removed }))), |
| 612 | workspaceStorageLayer, | 612 | scopeStorageLayer, |
| 613 | runtimeLocalWorkspace: input.runtimeLocalWorkspace, | 613 | runtimeLocalScope: input.runtimeLocalScope, |
| 614 | }), | 614 | }), |
| 615 | }, | 615 | }, |
| 616 | metadata, | 616 | metadata, |
| @@ -622,9 +622,9 @@ export const createWorkspaceExecutorAdminToolMap = ( · 5 unmodified lines | |||
| 622 | outputSchema: listPoliciesOutputSchema, | 622 | outputSchema: listPoliciesOutputSchema, |
| 623 | execute: () => | 623 | execute: () => |
| 624 | runRuntimeEffect({ | 624 | runRuntimeEffect({ |
| 625 | effect: listPolicies(input.workspaceId), | 625 | effect: listPolicies(input.scopeId), |
| 626 | runtimeLayer, | 626 | runtimeLayer, |
| 627 | runtimeLocalWorkspace: input.runtimeLocalWorkspace, | 627 | runtimeLocalScope: input.runtimeLocalScope, |
| 628 | }), | 628 | }), |
| 629 | }, | 629 | }, |
| 630 | metadata, | 630 | metadata, |
| @@ -633,15 +633,15 @@ export const createWorkspaceExecutorAdminToolMap = ( · 2 unmodified lines | |||
| 633 | tool: { | 633 | tool: { |
| 634 | description: "Create a local workspace policy.", | 634 | description: "Create a local workspace policy.", |
| 635 | inputSchema: createPolicyInputSchema, | 635 | inputSchema: createPolicyInputSchema, |
| 636 | outputSchema: localWorkspacePolicyOutputSchema, | 636 | outputSchema: localScopePolicyOutputSchema, |
| 637 | execute: (payload: CreatePolicyPayload) => | 637 | execute: (payload: CreatePolicyPayload) => |
| 638 | runRuntimeEffect({ | 638 | runRuntimeEffect({ |
| 639 | effect: createPolicy({ | 639 | effect: createPolicy({ |
| 640 | workspaceId: input.workspaceId, | 640 | scopeId: input.scopeId, |
| 641 | payload, | 641 | payload, |
| 642 | }), | 642 | }), |
| 643 | runtimeLayer, | 643 | runtimeLayer, |
| 644 | runtimeLocalWorkspace: input.runtimeLocalWorkspace, | 644 | runtimeLocalScope: input.runtimeLocalScope, |
| 645 | }), | 645 | }), |
| 646 | }, | 646 | }, |
| 647 | metadata, | 647 | metadata, |
| @@ -650,15 +650,15 @@ export const createWorkspaceExecutorAdminToolMap = ( · 2 unmodified lines | |||
| 650 | tool: { | 650 | tool: { |
| 651 | description: "Get one local workspace policy by id.", | 651 | description: "Get one local workspace policy by id.", |
| 652 | inputSchema: policyIdInputSchema, | 652 | inputSchema: policyIdInputSchema, |
| 653 | outputSchema: localWorkspacePolicyOutputSchema, | 653 | outputSchema: localScopePolicyOutputSchema, |
| 654 | execute: ({ policyId }: { policyId: string }) => | 654 | execute: ({ policyId }: { policyId: string }) => |
| 655 | runRuntimeEffect({ | 655 | runRuntimeEffect({ |
| 656 | effect: getPolicy({ | 656 | effect: getPolicy({ |
| 657 | workspaceId: input.workspaceId, | 657 | scopeId: input.scopeId, |
| 658 | policyId: policyId as never, | 658 | policyId: policyId as never, |
| 659 | }), | 659 | }), |
| 660 | runtimeLayer, | 660 | runtimeLayer, |
| 661 | runtimeLocalWorkspace: input.runtimeLocalWorkspace, | 661 | runtimeLocalScope: input.runtimeLocalScope, |
| 662 | }), | 662 | }), |
| 663 | }, | 663 | }, |
| 664 | metadata, | 664 | metadata, |
| @@ -667,7 +667,7 @@ export const createWorkspaceExecutorAdminToolMap = ( · 2 unmodified lines | |||
| 667 | tool: { | 667 | tool: { |
| 668 | description: "Update a local workspace policy.", | 668 | description: "Update a local workspace policy.", |
| 669 | inputSchema: updatePolicyInputSchema, | 669 | inputSchema: updatePolicyInputSchema, |
| 670 | outputSchema: localWorkspacePolicyOutputSchema, | 670 | outputSchema: localScopePolicyOutputSchema, |
| 671 | execute: ({ | 671 | execute: ({ |
| 672 | policyId, | 672 | policyId, |
| 673 | payload, | 673 | payload, |
| @@ -677,12 +677,12 @@ export const createWorkspaceExecutorAdminToolMap = ( · 3 unmodified lines | |||
| 677 | }) => | 677 | }) => |
| 678 | runRuntimeEffect({ | 678 | runRuntimeEffect({ |
| 679 | effect: updatePolicy({ | 679 | effect: updatePolicy({ |
| 680 | workspaceId: input.workspaceId, | 680 | scopeId: input.scopeId, |
| 681 | policyId: policyId as never, | 681 | policyId: policyId as never, |
| 682 | payload, | 682 | payload, |
| 683 | }), | 683 | }), |
| 684 | runtimeLayer, | 684 | runtimeLayer, |
| 685 | runtimeLocalWorkspace: input.runtimeLocalWorkspace, | 685 | runtimeLocalScope: input.runtimeLocalScope, |
| 686 | }), | 686 | }), |
| 687 | }, | 687 | }, |
| 688 | metadata, | 688 | metadata, |
| @@ -695,11 +695,11 @@ export const createWorkspaceExecutorAdminToolMap = ( · 6 unmodified lines | |||
| 695 | execute: ({ policyId }: { policyId: string }) => | 695 | execute: ({ policyId }: { policyId: string }) => |
| 696 | runRuntimeEffect({ | 696 | runRuntimeEffect({ |
| 697 | effect: removePolicy({ | 697 | effect: removePolicy({ |
| 698 | workspaceId: input.workspaceId, | 698 | scopeId: input.scopeId, |
| 699 | policyId: policyId as never, | 699 | policyId: policyId as never, |
| 700 | }), | 700 | }), |
| 701 | runtimeLayer, | 701 | runtimeLayer, |
| 702 | runtimeLocalWorkspace: input.runtimeLocalWorkspace, | 702 | runtimeLocalScope: input.runtimeLocalScope, |
| 703 | }), | 703 | }), |
| 704 | }, | 704 | }, |
| 705 | metadata, | 705 | metadata, |
| @@ -903,7 +903,7 @@ export const createExecutorAdminToolMap = (input: { · 197 unmodified lines | |||
| 903 | description: | 903 | description: |
| 904 | "Create a workspace OAuth client for a provider-backed source flow.", | 904 | "Create a workspace OAuth client for a provider-backed source flow.", |
| 905 | inputSchema: createWorkspaceOauthClientInputSchema, | 905 | inputSchema: createWorkspaceOauthClientInputSchema, |
| 906 | outputSchema: Schema.standardSchemaV1(WorkspaceOauthClientSchema), | 906 | outputSchema: Schema.standardSchemaV1(ScopeOauthClientSchema), |
| 907 | execute: (payload: CreateWorkspaceOauthClientPayload) => | 907 | execute: (payload: CreateWorkspaceOauthClientPayload) => |
| 908 | input.executor.sources.oauthClients.create(payload), | 908 | input.executor.sources.oauthClients.create(payload), |
| 909 | }, | 909 | }, |
| @@ -952,7 +952,7 @@ export const createExecutorAdminToolMap = (input: { · 42 unmodified lines | |||
| 952 | tool: { | 952 | tool: { |
| 953 | description: "Create a local workspace policy.", | 953 | description: "Create a local workspace policy.", |
| 954 | inputSchema: createPolicyInputSchema, | 954 | inputSchema: createPolicyInputSchema, |
| 955 | outputSchema: localWorkspacePolicyOutputSchema, | 955 | outputSchema: localScopePolicyOutputSchema, |
| 956 | execute: (payload: CreatePolicyPayload) => | 956 | execute: (payload: CreatePolicyPayload) => |
| 957 | input.executor.policies.create(payload), | 957 | input.executor.policies.create(payload), |
| 958 | }, | 958 | }, |
| @@ -962,7 +962,7 @@ export const createExecutorAdminToolMap = (input: { · 3 unmodified lines | |||
| 962 | tool: { | 962 | tool: { |
| 963 | description: "Get one local workspace policy by id.", | 963 | description: "Get one local workspace policy by id.", |
| 964 | inputSchema: policyIdInputSchema, | 964 | inputSchema: policyIdInputSchema, |
| 965 | outputSchema: localWorkspacePolicyOutputSchema, | 965 | outputSchema: localScopePolicyOutputSchema, |
| 966 | execute: ({ policyId }: { policyId: string }) => | 966 | execute: ({ policyId }: { policyId: string }) => |
| 967 | input.executor.policies.get(policyId), | 967 | input.executor.policies.get(policyId), |
| 968 | }, | 968 | }, |
| @@ -972,7 +972,7 @@ export const createExecutorAdminToolMap = (input: { · 3 unmodified lines | |||
| 972 | tool: { | 972 | tool: { |
| 973 | description: "Update a local workspace policy.", | 973 | description: "Update a local workspace policy.", |
| 974 | inputSchema: updatePolicyInputSchema, | 974 | inputSchema: updatePolicyInputSchema, |
| 975 | outputSchema: localWorkspacePolicyOutputSchema, | 975 | outputSchema: localScopePolicyOutputSchema, |
| 976 | execute: ({ | 976 | execute: ({ |
| 977 | policyId, | 977 | policyId, |
| 978 | payload, | 978 | payload, |
| @@ -34,7 +34,7 @@ describe("local-config", () => { · 33 unmodified lines | |||
| 34 | join(configDirectory, "executor.jsonc"), | 34 | join(configDirectory, "executor.jsonc"), |
| 35 | `{ | 35 | `{ |
| 36 | "runtime": "ses", | 36 | "runtime": "ses", |
| 37 | // local workspace config | 37 | // local scope config |
| 38 | "sources": { | 38 | "sources": { |
| 39 | "github": { | 39 | "github": { |
| 40 | "kind": "openapi", | 40 | "kind": "openapi", |
| @@ -16,8 +16,8 @@ import { · 15 unmodified lines | |||
| 16 | } from "@executor/platform-sdk/schema"; | 16 | } from "@executor/platform-sdk/schema"; |
| 17 | import * as Effect from "effect/Effect"; | 17 | import * as Effect from "effect/Effect"; |
| 18 | import * as Schema from "effect/Schema"; | 18 | import * as Schema from "effect/Schema"; |
| 19 | import type { ExecutorWorkspaceDescriptor } from "@executor/platform-sdk"; | 19 | import type { ExecutorScopeDescriptor } from "@executor/platform-sdk"; |
| 20 | import type { LoadedLocalExecutorConfig } from "../../sdk/src/runtime/workspace-config"; | 20 | import type { LoadedLocalExecutorConfig } from "../../sdk/src/runtime/scope-config"; |
| 21 | import { | 21 | import { |
| 22 | LocalExecutorConfigDecodeError, | 22 | LocalExecutorConfigDecodeError, |
| 23 | LocalFileSystemError, | 23 | LocalFileSystemError, |
| @@ -36,7 +36,7 @@ export const encodeLocalExecutorConfig = (config: LocalExecutorConfig): string = · 12 unmodified lines | |||
| 36 | 36 | ||
| 37 | export const resolveConfigRelativePath = (input: { | 37 | export const resolveConfigRelativePath = (input: { |
| 38 | path: string; | 38 | path: string; |
| 39 | workspaceRoot: string; | 39 | scopeRoot: string; |
| 40 | }): string => { | 40 | }): string => { |
| 41 | const trimmed = input.path.trim(); | 41 | const trimmed = input.path.trim(); |
| 42 | if (trimmed.startsWith("~/")) { | 42 | if (trimmed.startsWith("~/")) { |
| @@ -48,10 +48,10 @@ export const resolveConfigRelativePath = (input: { · 5 unmodified lines | |||
| 48 | if (isAbsolute(trimmed)) { | 48 | if (isAbsolute(trimmed)) { |
| 49 | return trimmed; | 49 | return trimmed; |
| 50 | } | 50 | } |
| 51 | return resolve(input.workspaceRoot, trimmed); | 51 | return resolve(input.scopeRoot, trimmed); |
| 52 | }; | 52 | }; |
| 53 | 53 | ||
| 54 | export type { LoadedLocalExecutorConfig } from "../../sdk/src/runtime/workspace-config"; | 54 | export type { LoadedLocalExecutorConfig } from "../../sdk/src/runtime/scope-config"; |
| 55 | 55 | ||
| 56 | const PROJECT_CONFIG_BASENAME = "executor.jsonc"; | 56 | const PROJECT_CONFIG_BASENAME = "executor.jsonc"; |
| 57 | const PROJECT_CONFIG_DIRECTORY = ".executor"; | 57 | const PROJECT_CONFIG_DIRECTORY = ".executor"; |
| @@ -52,7 +52,7 @@ describe("local-executor-state-store", () => { · 51 unmodified lines | |||
| 52 | authArtifacts: [], | 52 | authArtifacts: [], |
| 53 | authLeases: [], | 53 | authLeases: [], |
| 54 | sourceOauthClients: [], | 54 | sourceOauthClients: [], |
| 55 | workspaceOauthClients: [], | 55 | scopeOauthClients: [], |
| 56 | providerAuthGrants: [], | 56 | providerAuthGrants: [], |
| 57 | sourceAuthSessions: [], | 57 | sourceAuthSessions: [], |
| 58 | secretMaterials: [], | 58 | secretMaterials: [], |
| @@ -20,10 +20,10 @@ import { · 19 unmodified lines | |||
| 20 | type SecretMaterial, | 20 | type SecretMaterial, |
| 21 | type SourceAuthSession, | 21 | type SourceAuthSession, |
| 22 | SourceAuthSessionSchema, | 22 | SourceAuthSessionSchema, |
| 23 | type WorkspaceOauthClient, | 23 | type ScopeOauthClient, |
| 24 | WorkspaceOauthClientSchema, | 24 | ScopeOauthClientSchema, |
| 25 | type WorkspaceSourceOauthClient, | 25 | type ScopedSourceOauthClient, |
| 26 | WorkspaceSourceOauthClientSchema, | 26 | ScopedSourceOauthClientSchema, |
| 27 | } from "@executor/platform-sdk/schema"; | 27 | } from "@executor/platform-sdk/schema"; |
| 28 | import * as Effect from "effect/Effect"; | 28 | import * as Effect from "effect/Effect"; |
| 29 | import * as Option from "effect/Option"; | 29 | import * as Option from "effect/Option"; |
| @@ -43,8 +43,8 @@ const LocalExecutorStateSnapshotSchema = Schema.Struct({ · 13 unmodified lines | |||
| 43 | version: Schema.Literal(LOCAL_EXECUTOR_STATE_VERSION), | 43 | version: Schema.Literal(LOCAL_EXECUTOR_STATE_VERSION), |
| 44 | authArtifacts: Schema.Array(AuthArtifactSchema), | 44 | authArtifacts: Schema.Array(AuthArtifactSchema), |
| 45 | authLeases: Schema.Array(AuthLeaseSchema), | 45 | authLeases: Schema.Array(AuthLeaseSchema), |
| 46 | sourceOauthClients: Schema.Array(WorkspaceSourceOauthClientSchema), | 46 | sourceOauthClients: Schema.Array(ScopedSourceOauthClientSchema), |
| 47 | workspaceOauthClients: Schema.Array(WorkspaceOauthClientSchema), | 47 | scopeOauthClients: Schema.Array(ScopeOauthClientSchema), |
| 48 | providerAuthGrants: Schema.Array(ProviderAuthGrantSchema), | 48 | providerAuthGrants: Schema.Array(ProviderAuthGrantSchema), |
| 49 | sourceAuthSessions: Schema.Array(SourceAuthSessionSchema), | 49 | sourceAuthSessions: Schema.Array(SourceAuthSessionSchema), |
| 50 | secretMaterials: Schema.Array(SecretMaterialSchema), | 50 | secretMaterials: Schema.Array(SecretMaterialSchema), |
| @@ -69,7 +69,7 @@ const defaultLocalExecutorStateSnapshot = (): LocalExecutorStateSnapshot => ({ · 18 unmodified lines | |||
| 69 | authArtifacts: [], | 69 | authArtifacts: [], |
| 70 | authLeases: [], | 70 | authLeases: [], |
| 71 | sourceOauthClients: [], | 71 | sourceOauthClients: [], |
| 72 | workspaceOauthClients: [], | 72 | scopeOauthClients: [], |
| 73 | providerAuthGrants: [], | 73 | providerAuthGrants: [], |
| 74 | sourceAuthSessions: [], | 74 | sourceAuthSessions: [], |
| 75 | secretMaterials: [], | 75 | secretMaterials: [], |
| @@ -114,7 +114,7 @@ const localExecutorStatePath = ( · 38 unmodified lines | |||
| 114 | join( | 114 | join( |
| 115 | context.homeStateDirectory, | 115 | context.homeStateDirectory, |
| 116 | "workspaces", | 116 | "workspaces", |
| 117 | deriveLocalInstallation(context).workspaceId, | 117 | deriveLocalInstallation(context).scopeId, |
| 118 | LOCAL_EXECUTOR_STATE_BASENAME, | 118 | LOCAL_EXECUTOR_STATE_BASENAME, |
| 119 | ); | 119 | ); |
| 120 | 120 | ||
| @@ -230,9 +230,9 @@ const mergeAuthArtifacts = ( · 109 unmodified lines | |||
| 230 | for (const artifact of imported) { | 230 | for (const artifact of imported) { |
| 231 | merged.set( | 231 | merged.set( |
| 232 | [ | 232 | [ |
| 233 | artifact.workspaceId, | 233 | artifact.scopeId, |
| 234 | artifact.sourceId, | 234 | artifact.sourceId, |
| 235 | artifact.actorAccountId ?? "", | 235 | artifact.actorScopeId ?? "", |
| 236 | artifact.slot, | 236 | artifact.slot, |
| 237 | ].join("::"), | 237 | ].join("::"), |
| 238 | cloneValue(artifact), | 238 | cloneValue(artifact), |
| @@ -242,9 +242,9 @@ const mergeAuthArtifacts = ( · 3 unmodified lines | |||
| 242 | for (const artifact of current) { | 242 | for (const artifact of current) { |
| 243 | merged.set( | 243 | merged.set( |
| 244 | [ | 244 | [ |
| 245 | artifact.workspaceId, | 245 | artifact.scopeId, |
| 246 | artifact.sourceId, | 246 | artifact.sourceId, |
| 247 | artifact.actorAccountId ?? "", | 247 | artifact.actorScopeId ?? "", |
| 248 | artifact.slot, | 248 | artifact.slot, |
| 249 | ].join("::"), | 249 | ].join("::"), |
| 250 | cloneValue(artifact), | 250 | cloneValue(artifact), |
| @@ -255,14 +255,14 @@ const mergeAuthArtifacts = ( · 4 unmodified lines | |||
| 255 | }; | 255 | }; |
| 256 | 256 | ||
| 257 | const mergeSourceOauthClients = ( | 257 | const mergeSourceOauthClients = ( |
| 258 | current: readonly WorkspaceSourceOauthClient[], | 258 | current: readonly ScopedSourceOauthClient[], |
| 259 | imported: readonly WorkspaceSourceOauthClient[], | 259 | imported: readonly ScopedSourceOauthClient[], |
| 260 | ): WorkspaceSourceOauthClient[] => { | 260 | ): ScopedSourceOauthClient[] => { |
| 261 | const merged = new Map<string, WorkspaceSourceOauthClient>(); | 261 | const merged = new Map<string, ScopedSourceOauthClient>(); |
| 262 | 262 | ||
| 263 | for (const oauthClient of imported) { | 263 | for (const oauthClient of imported) { |
| 264 | merged.set( | 264 | merged.set( |
| 265 | [oauthClient.workspaceId, oauthClient.sourceId, oauthClient.providerKey].join( | 265 | [oauthClient.scopeId, oauthClient.sourceId, oauthClient.providerKey].join( |
| 266 | "::", | 266 | "::", |
| 267 | ), | 267 | ), |
| 268 | cloneValue(oauthClient), | 268 | cloneValue(oauthClient), |
| @@ -271,7 +271,7 @@ const mergeSourceOauthClients = ( · 2 unmodified lines | |||
| 271 | 271 | ||
| 272 | for (const oauthClient of current) { | 272 | for (const oauthClient of current) { |
| 273 | merged.set( | 273 | merged.set( |
| 274 | [oauthClient.workspaceId, oauthClient.sourceId, oauthClient.providerKey].join( | 274 | [oauthClient.scopeId, oauthClient.sourceId, oauthClient.providerKey].join( |
| 275 | "::", | 275 | "::", |
| 276 | ), | 276 | ), |
| 277 | cloneValue(oauthClient), | 277 | cloneValue(oauthClient), |
| @@ -282,21 +282,21 @@ const mergeSourceOauthClients = ( · 4 unmodified lines | |||
| 282 | }; | 282 | }; |
| 283 | 283 | ||
| 284 | const mergeWorkspaceOauthClients = ( | 284 | const mergeWorkspaceOauthClients = ( |
| 285 | current: readonly WorkspaceOauthClient[], | 285 | current: readonly ScopeOauthClient[], |
| 286 | imported: readonly WorkspaceOauthClient[], | 286 | imported: readonly ScopeOauthClient[], |
| 287 | ): WorkspaceOauthClient[] => { | 287 | ): ScopeOauthClient[] => { |
| 288 | const merged = new Map<string, WorkspaceOauthClient>(); | 288 | const merged = new Map<string, ScopeOauthClient>(); |
| 289 | 289 | ||
| 290 | for (const oauthClient of imported) { | 290 | for (const oauthClient of imported) { |
| 291 | merged.set( | 291 | merged.set( |
| 292 | [oauthClient.workspaceId, oauthClient.providerKey, oauthClient.id].join("::"), | 292 | [oauthClient.scopeId, oauthClient.providerKey, oauthClient.id].join("::"), |
| 293 | cloneValue(oauthClient), | 293 | cloneValue(oauthClient), |
| 294 | ); | 294 | ); |
| 295 | } | 295 | } |
| 296 | 296 | ||
| 297 | for (const oauthClient of current) { | 297 | for (const oauthClient of current) { |
| 298 | merged.set( | 298 | merged.set( |
| 299 | [oauthClient.workspaceId, oauthClient.providerKey, oauthClient.id].join("::"), | 299 | [oauthClient.scopeId, oauthClient.providerKey, oauthClient.id].join("::"), |
| 300 | cloneValue(oauthClient), | 300 | cloneValue(oauthClient), |
| 301 | ); | 301 | ); |
| 302 | } | 302 | } |
| @@ -326,9 +326,9 @@ export const mergeImportedLocalExecutorStateSnapshot = (input: { · 23 unmodified lines | |||
| 326 | input.current.sourceOauthClients, | 326 | input.current.sourceOauthClients, |
| 327 | input.imported.sourceOauthClients ?? [], | 327 | input.imported.sourceOauthClients ?? [], |
| 328 | ), | 328 | ), |
| 329 | workspaceOauthClients: mergeWorkspaceOauthClients( | 329 | scopeOauthClients: mergeWorkspaceOauthClients( |
| 330 | input.current.workspaceOauthClients, | 330 | input.current.scopeOauthClients, |
| 331 | input.imported.workspaceOauthClients ?? [], | 331 | input.imported.scopeOauthClients ?? [], |
| 332 | ), | 332 | ), |
| 333 | providerAuthGrants: mergeProviderAuthGrants( | 333 | providerAuthGrants: mergeProviderAuthGrants( |
| 334 | input.current.providerAuthGrants, | 334 | input.current.providerAuthGrants, |
| @@ -440,40 +440,40 @@ export const createLocalExecutorStateStore = ( · 105 unmodified lines | |||
| 440 | 440 | ||
| 441 | return { | 441 | return { |
| 442 | authArtifacts: { | 442 | authArtifacts: { |
| 443 | listByWorkspaceId: (workspaceId: AuthArtifact["workspaceId"]) => | 443 | listByScopeId: (scopeId: AuthArtifact["scopeId"]) => |
| 444 | stateManager.read((state) => | 444 | stateManager.read((state) => |
| 445 | sortByUpdatedAtAndIdAsc( | 445 | sortByUpdatedAtAndIdAsc( |
| 446 | state.authArtifacts.filter((artifact) => artifact.workspaceId === workspaceId), | 446 | state.authArtifacts.filter((artifact) => artifact.scopeId === scopeId), |
| 447 | ), | 447 | ), |
| 448 | ), | 448 | ), |
| 449 | 449 | ||
| 450 | listByWorkspaceAndSourceId: (input: { | 450 | listByScopeAndSourceId: (input: { |
| 451 | workspaceId: AuthArtifact["workspaceId"]; | 451 | scopeId: AuthArtifact["scopeId"]; |
| 452 | sourceId: AuthArtifact["sourceId"]; | 452 | sourceId: AuthArtifact["sourceId"]; |
| 453 | }) => | 453 | }) => |
| 454 | stateManager.read((state) => | 454 | stateManager.read((state) => |
| 455 | sortByUpdatedAtAndIdAsc( | 455 | sortByUpdatedAtAndIdAsc( |
| 456 | state.authArtifacts.filter( | 456 | state.authArtifacts.filter( |
| 457 | (artifact) => | 457 | (artifact) => |
| 458 | artifact.workspaceId === input.workspaceId | 458 | artifact.scopeId === input.scopeId |
| 459 | && artifact.sourceId === input.sourceId, | 459 | && artifact.sourceId === input.sourceId, |
| 460 | ), | 460 | ), |
| 461 | ), | 461 | ), |
| 462 | ), | 462 | ), |
| 463 | 463 | ||
| 464 | getByWorkspaceSourceAndActor: (input: { | 464 | getByScopeSourceAndActor: (input: { |
| 465 | workspaceId: AuthArtifact["workspaceId"]; | 465 | scopeId: AuthArtifact["scopeId"]; |
| 466 | sourceId: AuthArtifact["sourceId"]; | 466 | sourceId: AuthArtifact["sourceId"]; |
| 467 | actorAccountId: AuthArtifact["actorAccountId"]; | 467 | actorScopeId: AuthArtifact["actorScopeId"]; |
| 468 | slot: AuthArtifact["slot"]; | 468 | slot: AuthArtifact["slot"]; |
| 469 | }) => | 469 | }) => |
| 470 | stateManager.read((state) => { | 470 | stateManager.read((state) => { |
| 471 | const artifact = state.authArtifacts.find( | 471 | const artifact = state.authArtifacts.find( |
| 472 | (candidate) => | 472 | (candidate) => |
| 473 | candidate.workspaceId === input.workspaceId | 473 | candidate.scopeId === input.scopeId |
| 474 | && candidate.sourceId === input.sourceId | 474 | && candidate.sourceId === input.sourceId |
| 475 | && candidate.slot === input.slot | 475 | && candidate.slot === input.slot |
| 476 | && actorEquals(candidate.actorAccountId, input.actorAccountId), | 476 | && actorEquals(candidate.actorScopeId, input.actorScopeId), |
| 477 | ); | 477 | ); |
| 478 | 478 | ||
| 479 | return artifact ? Option.some(cloneValue(artifact)) : Option.none<AuthArtifact>(); | 479 | return artifact ? Option.some(cloneValue(artifact)) : Option.none<AuthArtifact>(); |
| @@ -484,10 +484,10 @@ export const createLocalExecutorStateStore = ( · 4 unmodified lines | |||
| 484 | const nextArtifacts = state.authArtifacts.filter( | 484 | const nextArtifacts = state.authArtifacts.filter( |
| 485 | (candidate) => | 485 | (candidate) => |
| 486 | !( | 486 | !( |
| 487 | candidate.workspaceId === artifact.workspaceId | 487 | candidate.scopeId === artifact.scopeId |
| 488 | && candidate.sourceId === artifact.sourceId | 488 | && candidate.sourceId === artifact.sourceId |
| 489 | && candidate.slot === artifact.slot | 489 | && candidate.slot === artifact.slot |
| 490 | && actorEquals(candidate.actorAccountId, artifact.actorAccountId) | 490 | && actorEquals(candidate.actorScopeId, artifact.actorScopeId) |
| 491 | ), | 491 | ), |
| 492 | ); | 492 | ); |
| 493 | nextArtifacts.push(cloneValue(artifact)); | 493 | nextArtifacts.push(cloneValue(artifact)); |
| @@ -501,18 +501,18 @@ export const createLocalExecutorStateStore = ( · 7 unmodified lines | |||
| 501 | } satisfies StateMutationResult<void>; | 501 | } satisfies StateMutationResult<void>; |
| 502 | }), | 502 | }), |
| 503 | 503 | ||
| 504 | removeByWorkspaceSourceAndActor: (input: { | 504 | removeByScopeSourceAndActor: (input: { |
| 505 | workspaceId: AuthArtifact["workspaceId"]; | 505 | scopeId: AuthArtifact["scopeId"]; |
| 506 | sourceId: AuthArtifact["sourceId"]; | 506 | sourceId: AuthArtifact["sourceId"]; |
| 507 | actorAccountId: AuthArtifact["actorAccountId"]; | 507 | actorScopeId: AuthArtifact["actorScopeId"]; |
| 508 | slot?: AuthArtifact["slot"]; | 508 | slot?: AuthArtifact["slot"]; |
| 509 | }) => | 509 | }) => |
| 510 | stateManager.mutate((state) => { | 510 | stateManager.mutate((state) => { |
| 511 | const nextArtifacts = state.authArtifacts.filter( | 511 | const nextArtifacts = state.authArtifacts.filter( |
| 512 | (candidate) => | 512 | (candidate) => |
| 513 | candidate.workspaceId !== input.workspaceId | 513 | candidate.scopeId !== input.scopeId |
| 514 | || candidate.sourceId !== input.sourceId | 514 | || candidate.sourceId !== input.sourceId |
| 515 | || !actorEquals(candidate.actorAccountId, input.actorAccountId) | 515 | || !actorEquals(candidate.actorScopeId, input.actorScopeId) |
| 516 | || (input.slot !== undefined && candidate.slot !== input.slot), | 516 | || (input.slot !== undefined && candidate.slot !== input.slot), |
| 517 | ); | 517 | ); |
| 518 | 518 | ||
| @@ -525,14 +525,14 @@ export const createLocalExecutorStateStore = ( · 6 unmodified lines | |||
| 525 | } satisfies StateMutationResult<boolean>; | 525 | } satisfies StateMutationResult<boolean>; |
| 526 | }), | 526 | }), |
| 527 | 527 | ||
| 528 | removeByWorkspaceAndSourceId: (input: { | 528 | removeByScopeAndSourceId: (input: { |
| 529 | workspaceId: AuthArtifact["workspaceId"]; | 529 | scopeId: AuthArtifact["scopeId"]; |
| 530 | sourceId: AuthArtifact["sourceId"]; | 530 | sourceId: AuthArtifact["sourceId"]; |
| 531 | }) => | 531 | }) => |
| 532 | stateManager.mutate((state) => { | 532 | stateManager.mutate((state) => { |
| 533 | const nextArtifacts = state.authArtifacts.filter( | 533 | const nextArtifacts = state.authArtifacts.filter( |
| 534 | (candidate) => | 534 | (candidate) => |
| 535 | candidate.workspaceId !== input.workspaceId | 535 | candidate.scopeId !== input.scopeId |
| 536 | || candidate.sourceId !== input.sourceId, | 536 | || candidate.sourceId !== input.sourceId, |
| 537 | ); | 537 | ); |
| 538 | 538 | ||
| @@ -591,30 +591,30 @@ export const createLocalExecutorStateStore = ( · 52 unmodified lines | |||
| 591 | }, | 591 | }, |
| 592 | 592 | ||
| 593 | sourceOauthClients: { | 593 | sourceOauthClients: { |
| 594 | getByWorkspaceSourceAndProvider: (input: { | 594 | getByScopeSourceAndProvider: (input: { |
| 595 | workspaceId: WorkspaceSourceOauthClient["workspaceId"]; | 595 | scopeId: ScopedSourceOauthClient["scopeId"]; |
| 596 | sourceId: WorkspaceSourceOauthClient["sourceId"]; | 596 | sourceId: ScopedSourceOauthClient["sourceId"]; |
| 597 | providerKey: string; | 597 | providerKey: string; |
| 598 | }) => | 598 | }) => |
| 599 | stateManager.read((state) => { | 599 | stateManager.read((state) => { |
| 600 | const oauthClient = state.sourceOauthClients.find( | 600 | const oauthClient = state.sourceOauthClients.find( |
| 601 | (candidate) => | 601 | (candidate) => |
| 602 | candidate.workspaceId === input.workspaceId | 602 | candidate.scopeId === input.scopeId |
| 603 | && candidate.sourceId === input.sourceId | 603 | && candidate.sourceId === input.sourceId |
| 604 | && candidate.providerKey === input.providerKey, | 604 | && candidate.providerKey === input.providerKey, |
| 605 | ); | 605 | ); |
| 606 | 606 | ||
| 607 | return oauthClient | 607 | return oauthClient |
| 608 | ? Option.some(cloneValue(oauthClient)) | 608 | ? Option.some(cloneValue(oauthClient)) |
| 609 | : Option.none<WorkspaceSourceOauthClient>(); | 609 | : Option.none<ScopedSourceOauthClient>(); |
| 610 | }), | 610 | }), |
| 611 | 611 | ||
| 612 | upsert: (oauthClient: WorkspaceSourceOauthClient) => | 612 | upsert: (oauthClient: ScopedSourceOauthClient) => |
| 613 | stateManager.mutate((state) => { | 613 | stateManager.mutate((state) => { |
| 614 | const nextOauthClients = state.sourceOauthClients.filter( | 614 | const nextOauthClients = state.sourceOauthClients.filter( |
| 615 | (candidate) => | 615 | (candidate) => |
| 616 | !( | 616 | !( |
| 617 | candidate.workspaceId === oauthClient.workspaceId | 617 | candidate.scopeId === oauthClient.scopeId |
| 618 | && candidate.sourceId === oauthClient.sourceId | 618 | && candidate.sourceId === oauthClient.sourceId |
| 619 | && candidate.providerKey === oauthClient.providerKey | 619 | && candidate.providerKey === oauthClient.providerKey |
| 620 | ), | 620 | ), |
| @@ -630,14 +630,14 @@ export const createLocalExecutorStateStore = ( · 9 unmodified lines | |||
| 630 | } satisfies StateMutationResult<void>; | 630 | } satisfies StateMutationResult<void>; |
| 631 | }), | 631 | }), |
| 632 | 632 | ||
| 633 | removeByWorkspaceAndSourceId: (input: { | 633 | removeByScopeAndSourceId: (input: { |
| 634 | workspaceId: WorkspaceSourceOauthClient["workspaceId"]; | 634 | scopeId: ScopedSourceOauthClient["scopeId"]; |
| 635 | sourceId: WorkspaceSourceOauthClient["sourceId"]; | 635 | sourceId: ScopedSourceOauthClient["sourceId"]; |
| 636 | }) => | 636 | }) => |
| 637 | stateManager.mutate((state) => { | 637 | stateManager.mutate((state) => { |
| 638 | const nextOauthClients = state.sourceOauthClients.filter( | 638 | const nextOauthClients = state.sourceOauthClients.filter( |
| 639 | (candidate) => | 639 | (candidate) => |
| 640 | candidate.workspaceId !== input.workspaceId | 640 | candidate.scopeId !== input.scopeId |
| 641 | || candidate.sourceId !== input.sourceId, | 641 | || candidate.sourceId !== input.sourceId, |
| 642 | ); | 642 | ); |
| 643 | 643 | ||
| @@ -651,35 +651,35 @@ export const createLocalExecutorStateStore = ( · 7 unmodified lines | |||
| 651 | }), | 651 | }), |
| 652 | }, | 652 | }, |
| 653 | 653 | ||
| 654 | workspaceOauthClients: { | 654 | scopeOauthClients: { |
| 655 | listByWorkspaceAndProvider: (input: { | 655 | listByScopeAndProvider: (input: { |
| 656 | workspaceId: WorkspaceOauthClient["workspaceId"]; | 656 | scopeId: ScopeOauthClient["scopeId"]; |
| 657 | providerKey: string; | 657 | providerKey: string; |
| 658 | }) => | 658 | }) => |
| 659 | stateManager.read((state) => | 659 | stateManager.read((state) => |
| 660 | sortByUpdatedAtAndIdAsc( | 660 | sortByUpdatedAtAndIdAsc( |
| 661 | state.workspaceOauthClients.filter( | 661 | state.scopeOauthClients.filter( |
| 662 | (candidate) => | 662 | (candidate) => |
| 663 | candidate.workspaceId === input.workspaceId | 663 | candidate.scopeId === input.scopeId |
| 664 | && candidate.providerKey === input.providerKey, | 664 | && candidate.providerKey === input.providerKey, |
| 665 | ), | 665 | ), |
| 666 | ), | 666 | ), |
| 667 | ), | 667 | ), |
| 668 | 668 | ||
| 669 | getById: (id: WorkspaceOauthClient["id"]) => | 669 | getById: (id: ScopeOauthClient["id"]) => |
| 670 | stateManager.read((state) => { | 670 | stateManager.read((state) => { |
| 671 | const oauthClient = state.workspaceOauthClients.find( | 671 | const oauthClient = state.scopeOauthClients.find( |
| 672 | (candidate) => candidate.id === id, | 672 | (candidate) => candidate.id === id, |
| 673 | ); | 673 | ); |
| 674 | 674 | ||
| 675 | return oauthClient | 675 | return oauthClient |
| 676 | ? Option.some(cloneValue(oauthClient)) | 676 | ? Option.some(cloneValue(oauthClient)) |
| 677 | : Option.none<WorkspaceOauthClient>(); | 677 | : Option.none<ScopeOauthClient>(); |
| 678 | }), | 678 | }), |
| 679 | 679 | ||
| 680 | upsert: (oauthClient: WorkspaceOauthClient) => | 680 | upsert: (oauthClient: ScopeOauthClient) => |
| 681 | stateManager.mutate((state) => { | 681 | stateManager.mutate((state) => { |
| 682 | const nextOauthClients = state.workspaceOauthClients.filter( | 682 | const nextOauthClients = state.scopeOauthClients.filter( |
| 683 | (candidate) => candidate.id !== oauthClient.id, | 683 | (candidate) => candidate.id !== oauthClient.id, |
| 684 | ); | 684 | ); |
| 685 | nextOauthClients.push(cloneValue(oauthClient)); | 685 | nextOauthClients.push(cloneValue(oauthClient)); |
| @@ -687,50 +687,50 @@ export const createLocalExecutorStateStore = ( · 1 unmodified line | |||
| 687 | return { | 687 | return { |
| 688 | state: { | 688 | state: { |
| 689 | ...state, | 689 | ...state, |
| 690 | workspaceOauthClients: nextOauthClients, | 690 | scopeOauthClients: nextOauthClients, |
| 691 | }, | 691 | }, |
| 692 | value: undefined, | 692 | value: undefined, |
| 693 | } satisfies StateMutationResult<void>; | 693 | } satisfies StateMutationResult<void>; |
| 694 | }), | 694 | }), |
| 695 | 695 | ||
| 696 | removeById: (id: WorkspaceOauthClient["id"]) => | 696 | removeById: (id: ScopeOauthClient["id"]) => |
| 697 | stateManager.mutate((state) => { | 697 | stateManager.mutate((state) => { |
| 698 | const nextOauthClients = state.workspaceOauthClients.filter( | 698 | const nextOauthClients = state.scopeOauthClients.filter( |
| 699 | (candidate) => candidate.id !== id, | 699 | (candidate) => candidate.id !== id, |
| 700 | ); | 700 | ); |
| 701 | 701 | ||
| 702 | return { | 702 | return { |
| 703 | state: { | 703 | state: { |
| 704 | ...state, | 704 | ...state, |
| 705 | workspaceOauthClients: nextOauthClients, | 705 | scopeOauthClients: nextOauthClients, |
| 706 | }, | 706 | }, |
| 707 | value: nextOauthClients.length !== state.workspaceOauthClients.length, | 707 | value: nextOauthClients.length !== state.scopeOauthClients.length, |
| 708 | } satisfies StateMutationResult<boolean>; | 708 | } satisfies StateMutationResult<boolean>; |
| 709 | }), | 709 | }), |
| 710 | }, | 710 | }, |
| 711 | 711 | ||
| 712 | providerAuthGrants: { | 712 | providerAuthGrants: { |
| 713 | listByWorkspaceId: (workspaceId: ProviderAuthGrant["workspaceId"]) => | 713 | listByScopeId: (scopeId: ProviderAuthGrant["scopeId"]) => |
| 714 | stateManager.read((state) => | 714 | stateManager.read((state) => |
| 715 | sortByUpdatedAtAndIdAsc( | 715 | sortByUpdatedAtAndIdAsc( |
| 716 | state.providerAuthGrants.filter( | 716 | state.providerAuthGrants.filter( |
| 717 | (grant) => grant.workspaceId === workspaceId, | 717 | (grant) => grant.scopeId === scopeId, |
| 718 | ), | 718 | ), |
| 719 | ), | 719 | ), |
| 720 | ), | 720 | ), |
| 721 | 721 | ||
| 722 | listByWorkspaceActorAndProvider: (input: { | 722 | listByScopeActorAndProvider: (input: { |
| 723 | workspaceId: ProviderAuthGrant["workspaceId"]; | 723 | scopeId: ProviderAuthGrant["scopeId"]; |
| 724 | actorAccountId: ProviderAuthGrant["actorAccountId"]; | 724 | actorScopeId: ProviderAuthGrant["actorScopeId"]; |
| 725 | providerKey: string; | 725 | providerKey: string; |
| 726 | }) => | 726 | }) => |
| 727 | stateManager.read((state) => | 727 | stateManager.read((state) => |
| 728 | sortByUpdatedAtAndIdAsc( | 728 | sortByUpdatedAtAndIdAsc( |
| 729 | state.providerAuthGrants.filter( | 729 | state.providerAuthGrants.filter( |
| 730 | (grant) => | 730 | (grant) => |
| 731 | grant.workspaceId === input.workspaceId | 731 | grant.scopeId === input.scopeId |
| 732 | && grant.providerKey === input.providerKey | 732 | && grant.providerKey === input.providerKey |
| 733 | && actorEquals(grant.actorAccountId, input.actorAccountId), | 733 | && actorEquals(grant.actorScopeId, input.actorScopeId), |
| 734 | ), | 734 | ), |
| 735 | ), | 735 | ), |
| 736 | ), | 736 | ), |
| @@ -782,11 +782,11 @@ export const createLocalExecutorStateStore = ( · 45 unmodified lines | |||
| 782 | listAll: () => | 782 | listAll: () => |
| 783 | stateManager.read((state) => sortByUpdatedAtAndIdAsc(state.sourceAuthSessions)), | 783 | stateManager.read((state) => sortByUpdatedAtAndIdAsc(state.sourceAuthSessions)), |
| 784 | 784 | ||
| 785 | listByWorkspaceId: (workspaceId: SourceAuthSession["workspaceId"]) => | 785 | listByScopeId: (scopeId: SourceAuthSession["scopeId"]) => |
| 786 | stateManager.read((state) => | 786 | stateManager.read((state) => |
| 787 | sortByUpdatedAtAndIdAsc( | 787 | sortByUpdatedAtAndIdAsc( |
| 788 | state.sourceAuthSessions.filter( | 788 | state.sourceAuthSessions.filter( |
| 789 | (session) => session.workspaceId === workspaceId, | 789 | (session) => session.scopeId === scopeId, |
| 790 | ), | 790 | ), |
| 791 | ), | 791 | ), |
| 792 | ), | 792 | ), |
| @@ -811,20 +811,20 @@ export const createLocalExecutorStateStore = ( · 18 unmodified lines | |||
| 811 | : Option.none<SourceAuthSession>(); | 811 | : Option.none<SourceAuthSession>(); |
| 812 | }), | 812 | }), |
| 813 | 813 | ||
| 814 | getPendingByWorkspaceSourceAndActor: (input: { | 814 | getPendingByScopeSourceAndActor: (input: { |
| 815 | workspaceId: SourceAuthSession["workspaceId"]; | 815 | scopeId: SourceAuthSession["scopeId"]; |
| 816 | sourceId: SourceAuthSession["sourceId"]; | 816 | sourceId: SourceAuthSession["sourceId"]; |
| 817 | actorAccountId: SourceAuthSession["actorAccountId"]; | 817 | actorScopeId: SourceAuthSession["actorScopeId"]; |
| 818 | credentialSlot?: SourceAuthSession["credentialSlot"]; | 818 | credentialSlot?: SourceAuthSession["credentialSlot"]; |
| 819 | }) => | 819 | }) => |
| 820 | stateManager.read((state) => { | 820 | stateManager.read((state) => { |
| 821 | const session = sortByUpdatedAtAndIdAsc( | 821 | const session = sortByUpdatedAtAndIdAsc( |
| 822 | state.sourceAuthSessions.filter( | 822 | state.sourceAuthSessions.filter( |
| 823 | (candidate) => | 823 | (candidate) => |
| 824 | candidate.workspaceId === input.workspaceId | 824 | candidate.scopeId === input.scopeId |
| 825 | && candidate.sourceId === input.sourceId | 825 | && candidate.sourceId === input.sourceId |
| 826 | && candidate.status === "pending" | 826 | && candidate.status === "pending" |
| 827 | && actorEquals(candidate.actorAccountId, input.actorAccountId) | 827 | && actorEquals(candidate.actorScopeId, input.actorScopeId) |
| 828 | && (input.credentialSlot === undefined | 828 | && (input.credentialSlot === undefined |
| 829 | || candidate.credentialSlot === input.credentialSlot), | 829 | || candidate.credentialSlot === input.credentialSlot), |
| 830 | ), | 830 | ), |
| @@ -846,7 +846,7 @@ export const createLocalExecutorStateStore = ( · 15 unmodified lines | |||
| 846 | 846 | ||
| 847 | update: ( | 847 | update: ( |
| 848 | id: SourceAuthSession["id"], | 848 | id: SourceAuthSession["id"], |
| 849 | patch: Partial<Omit<SourceAuthSession, "id" | "workspaceId" | "sourceId" | "createdAt">>, | 849 | patch: Partial<Omit<SourceAuthSession, "id" | "scopeId" | "sourceId" | "createdAt">>, |
| 850 | ) => | 850 | ) => |
| 851 | stateManager.mutate((state) => { | 851 | stateManager.mutate((state) => { |
| 852 | let updated: SourceAuthSession | null = null; | 852 | let updated: SourceAuthSession | null = null; |
| @@ -887,14 +887,14 @@ export const createLocalExecutorStateStore = ( · 34 unmodified lines | |||
| 887 | } satisfies StateMutationResult<void>; | 887 | } satisfies StateMutationResult<void>; |
| 888 | }), | 888 | }), |
| 889 | 889 | ||
| 890 | removeByWorkspaceAndSourceId: ( | 890 | removeByScopeAndSourceId: ( |
| 891 | workspaceId: SourceAuthSession["workspaceId"], | 891 | scopeId: SourceAuthSession["scopeId"], |
| 892 | sourceId: SourceAuthSession["sourceId"], | 892 | sourceId: SourceAuthSession["sourceId"], |
| 893 | ) => | 893 | ) => |
| 894 | stateManager.mutate((state) => { | 894 | stateManager.mutate((state) => { |
| 895 | const nextSessions = state.sourceAuthSessions.filter( | 895 | const nextSessions = state.sourceAuthSessions.filter( |
| 896 | (candidate) => | 896 | (candidate) => |
| 897 | candidate.workspaceId !== workspaceId || candidate.sourceId !== sourceId, | 897 | candidate.scopeId !== scopeId || candidate.sourceId !== sourceId, |
| 898 | ); | 898 | ); |
| 899 | 899 | ||
| 900 | return { | 900 | return { |
| @@ -993,14 +993,14 @@ export const createLocalExecutorStateStore = ( · 92 unmodified lines | |||
| 993 | : Option.none<Execution>(); | 993 | : Option.none<Execution>(); |
| 994 | }), | 994 | }), |
| 995 | 995 | ||
| 996 | getByWorkspaceAndId: ( | 996 | getByScopeAndId: ( |
| 997 | workspaceId: Execution["workspaceId"], | 997 | scopeId: Execution["scopeId"], |
| 998 | executionId: Execution["id"], | 998 | executionId: Execution["id"], |
| 999 | ) => | 999 | ) => |
| 1000 | stateManager.read((state) => { | 1000 | stateManager.read((state) => { |
| 1001 | const execution = state.executions.find( | 1001 | const execution = state.executions.find( |
| 1002 | (candidate) => | 1002 | (candidate) => |
| 1003 | candidate.workspaceId === workspaceId && candidate.id === executionId, | 1003 | candidate.scopeId === scopeId && candidate.id === executionId, |
| 1004 | ); | 1004 | ); |
| 1005 | return execution | 1005 | return execution |
| 1006 | ? Option.some(cloneValue(execution)) | 1006 | ? Option.some(cloneValue(execution)) |
| @@ -1019,7 +1019,7 @@ export const createLocalExecutorStateStore = ( · 12 unmodified lines | |||
| 1019 | update: ( | 1019 | update: ( |
| 1020 | executionId: Execution["id"], | 1020 | executionId: Execution["id"], |
| 1021 | patch: Partial< | 1021 | patch: Partial< |
| 1022 | Omit<Execution, "id" | "workspaceId" | "createdByAccountId" | "createdAt"> | 1022 | Omit<Execution, "id" | "scopeId" | "createdByAccountId" | "createdAt"> |
| 1023 | >, | 1023 | >, |
| 1024 | ) => | 1024 | ) => |
| 1025 | stateManager.mutate((state) => { | 1025 | stateManager.mutate((state) => { |
| @@ -10,7 +10,7 @@ import { · 9 unmodified lines | |||
| 10 | type ExecutorBackendServices, | 10 | type ExecutorBackendServices, |
| 11 | type ExecutorLocalToolBackend, | 11 | type ExecutorLocalToolBackend, |
| 12 | type ExecutorSourceTypeDeclarationsBackend, | 12 | type ExecutorSourceTypeDeclarationsBackend, |
| 13 | type ExecutorWorkspaceDescriptor, | 13 | type ExecutorScopeDescriptor, |
| 14 | } from "@executor/platform-sdk"; | 14 | } from "@executor/platform-sdk"; |
| 15 | import type { | 15 | import type { |
| 16 | LocalExecutorConfig, | 16 | LocalExecutorConfig, |
| @@ -198,11 +198,11 @@ const createBoundSourceTypeDeclarationsRefresher = ( · 181 unmodified lines | |||
| 198 | }), | 198 | }), |
| 199 | }); | 199 | }); |
| 200 | 200 | ||
| 201 | const toExecutorWorkspaceContext = ( | 201 | const toExecutorScopeContext = ( |
| 202 | context: ResolvedLocalWorkspaceContext, | 202 | context: ResolvedLocalWorkspaceContext, |
| 203 | ): ExecutorWorkspaceDescriptor => ({ | 203 | ): ExecutorScopeDescriptor => ({ |
| 204 | workspaceName: context.workspaceName, | 204 | scopeName: context.workspaceName, |
| 205 | workspaceRoot: context.workspaceRoot, | 205 | scopeRoot: context.workspaceRoot, |
| 206 | metadata: { | 206 | metadata: { |
| 207 | kind: "file", | 207 | kind: "file", |
| 208 | configDirectory: context.configDirectory, | 208 | configDirectory: context.configDirectory, |
| @@ -248,11 +248,11 @@ export const createLocalExecutorServicesEffect = ( · 39 unmodified lines | |||
| 248 | }); | 248 | }); |
| 249 | 249 | ||
| 250 | return { | 250 | return { |
| 251 | workspace: toExecutorWorkspaceContext(workspaceContext), | 251 | scope: toExecutorScopeContext(workspaceContext), |
| 252 | storage: { | 252 | storage: { |
| 253 | installation: createBoundInstallationStore(workspaceContext), | 253 | installation: createBoundInstallationStore(workspaceContext), |
| 254 | workspaceConfig: workspaceConfigStore, | 254 | scopeConfig: workspaceConfigStore, |
| 255 | workspaceState: createBoundWorkspaceStateStore( | 255 | scopeState: createBoundWorkspaceStateStore( |
| 256 | workspaceContext, | 256 | workspaceContext, |
| 257 | fileSystem, | 257 | fileSystem, |
| 258 | ), | 258 | ), |
| @@ -42,8 +42,8 @@ describe("local-installation", () => { · 41 unmodified lines | |||
| 42 | const installation = runtime.localInstallation; | 42 | const installation = runtime.localInstallation; |
| 43 | const fs = yield* FileSystem.FileSystem; | 43 | const fs = yield* FileSystem.FileSystem; |
| 44 | 44 | ||
| 45 | expect(installation.accountId).toBe("acc_local_default"); | 45 | expect(installation.actorScopeId).toBe("acc_local_default"); |
| 46 | expect(installation.workspaceId.startsWith("ws_local_")).toBe(true); | 46 | expect(installation.scopeId.startsWith("ws_local_")).toBe(true); |
| 47 | expect(yield* fs.exists(join(workspaceRoot, ".executor", "executor.jsonc"))).toBe(false); | 47 | expect(yield* fs.exists(join(workspaceRoot, ".executor", "executor.jsonc"))).toBe(false); |
| 48 | }).pipe(Effect.provide(NodeFileSystem.layer)), | 48 | }).pipe(Effect.provide(NodeFileSystem.layer)), |
| 49 | 60_000, | 49 | 60_000, |
| @@ -63,8 +63,8 @@ describe("local-installation", () => { · 13 unmodified lines | |||
| 63 | context, | 63 | context, |
| 64 | }); | 64 | }); |
| 65 | 65 | ||
| 66 | expect(second.accountId).toBe(first.accountId); | 66 | expect(second.actorScopeId).toBe(first.actorScopeId); |
| 67 | expect(second.workspaceId).toBe(first.workspaceId); | 67 | expect(second.scopeId).toBe(first.scopeId); |
| 68 | }).pipe(Effect.provide(NodeFileSystem.layer)), | 68 | }).pipe(Effect.provide(NodeFileSystem.layer)), |
| 69 | ); | 69 | ); |
| 70 | }); | 70 | }); |
| @@ -1,15 +1,14 @@ | |||
| 1 | import { createHash } from "node:crypto"; | 1 | import { createHash } from "node:crypto"; |
| 2 | 2 | ||
| 3 | import { | 3 | import { |
| 4 | AccountIdSchema, | 4 | ScopeIdSchema, |
| 5 | WorkspaceIdSchema, | ||
| 6 | type LocalInstallation, | 5 | type LocalInstallation, |
| 7 | } from "@executor/platform-sdk/schema"; | 6 | } from "@executor/platform-sdk/schema"; |
| 8 | import * as Effect from "effect/Effect"; | 7 | import * as Effect from "effect/Effect"; |
| 9 | 8 | ||
| 10 | import type { ResolvedLocalWorkspaceContext } from "./config"; | 9 | import type { ResolvedLocalWorkspaceContext } from "./config"; |
| 11 | 10 | ||
| 12 | const LOCAL_ACCOUNT_ID = AccountIdSchema.make("acc_local_default"); | 11 | const LOCAL_ACCOUNT_ID = ScopeIdSchema.make("acc_local_default"); |
| 13 | 12 | ||
| 14 | const stableHash = (value: string): string => | 13 | const stableHash = (value: string): string => |
| 15 | createHash("sha256").update(value).digest("hex").slice(0, 16); | 14 | createHash("sha256").update(value).digest("hex").slice(0, 16); |
| @@ -18,15 +17,19 @@ const normalizeSlashPath = (value: string): string => · 2 unmodified lines | |||
| 18 | value.replaceAll("\\", "/"); | 17 | value.replaceAll("\\", "/"); |
| 19 | 18 | ||
| 20 | const deriveWorkspaceId = (context: ResolvedLocalWorkspaceContext) => | 19 | const deriveWorkspaceId = (context: ResolvedLocalWorkspaceContext) => |
| 21 | WorkspaceIdSchema.make( | 20 | ScopeIdSchema.make( |
| 22 | `ws_local_${stableHash(normalizeSlashPath(context.workspaceRoot))}`, | 21 | `ws_local_${stableHash(normalizeSlashPath(context.workspaceRoot))}`, |
| 23 | ); | 22 | ); |
| 24 | 23 | ||
| 25 | export const deriveLocalInstallation = ( | 24 | export const deriveLocalInstallation = ( |
| 26 | context: ResolvedLocalWorkspaceContext, | 25 | context: ResolvedLocalWorkspaceContext, |
| 27 | ): LocalInstallation => ({ | 26 | ): LocalInstallation => ({ |
| 28 | accountId: LOCAL_ACCOUNT_ID, | 27 | actorScopeId: LOCAL_ACCOUNT_ID, |
| 29 | workspaceId: deriveWorkspaceId(context), | 28 | scopeId: deriveWorkspaceId(context), |
| 29 | resolutionScopeIds: [ | ||
| 30 | deriveWorkspaceId(context), | ||
| 31 | LOCAL_ACCOUNT_ID, | ||
| 32 | ], | ||
| 30 | }); | 33 | }); |
| 31 | 34 | ||
| 32 | export const loadLocalInstallation = ( | 35 | export const loadLocalInstallation = ( |
| @@ -28,9 +28,9 @@ import { · 27 unmodified lines | |||
| 28 | type StoreSecretMaterial, | 28 | type StoreSecretMaterial, |
| 29 | type DeleteSecretMaterial, | 29 | type DeleteSecretMaterial, |
| 30 | type UpdateSecretMaterial, | 30 | type UpdateSecretMaterial, |
| 31 | } from "../../sdk/src/runtime/workspace/secret-material-providers"; | 31 | } from "../../sdk/src/runtime/scope/secret-material-providers"; |
| 32 | import { fromConfigSecretProviderId } from "../../sdk/src/runtime/workspace/config-secrets"; | 32 | import { fromConfigSecretProviderId } from "../../sdk/src/runtime/scope/config-secrets"; |
| 33 | import { getRuntimeLocalWorkspaceOption } from "../../sdk/src/runtime/workspace/runtime-context"; | 33 | import { getRuntimeLocalScopeOption } from "../../sdk/src/runtime/scope/runtime-context"; |
| 34 | import { | 34 | import { |
| 35 | ExecutorStateStore, | 35 | ExecutorStateStore, |
| 36 | type ExecutorStateStoreShape, | 36 | type ExecutorStateStoreShape, |
| @@ -876,7 +876,7 @@ const readFileSecretValue = (input: { · 839 unmodified lines | |||
| 876 | const fs = yield* FileSystem.FileSystem; | 876 | const fs = yield* FileSystem.FileSystem; |
| 877 | const resolvedPath = resolveConfigRelativePath({ | 877 | const resolvedPath = resolveConfigRelativePath({ |
| 878 | path: input.provider.path, | 878 | path: input.provider.path, |
| 879 | workspaceRoot: input.workspaceRoot, | 879 | scopeRoot: input.workspaceRoot, |
| 880 | }); | 880 | }); |
| 881 | const raw = yield* fs.readFileString(resolvedPath, "utf8").pipe( | 881 | const raw = yield* fs.readFileString(resolvedPath, "utf8").pipe( |
| 882 | Effect.mapError(toError), | 882 | Effect.mapError(toError), |
| @@ -1140,14 +1140,14 @@ const resolveRuntimeSecretMaterialConfig = (input: { · 257 unmodified lines | |||
| 1140 | workspaceRoot?: string | null; | 1140 | workspaceRoot?: string | null; |
| 1141 | }) => | 1141 | }) => |
| 1142 | Effect.gen(function* () { | 1142 | Effect.gen(function* () { |
| 1143 | const runtimeLocalWorkspace = yield* getRuntimeLocalWorkspaceOption(); | 1143 | const runtimeLocalScope = yield* getRuntimeLocalScopeOption(); |
| 1144 | 1144 | ||
| 1145 | return { | 1145 | return { |
| 1146 | localConfig: input.localConfig | 1146 | localConfig: input.localConfig |
| 1147 | ?? runtimeLocalWorkspace?.loadedConfig.config | 1147 | ?? runtimeLocalScope?.loadedConfig.config |
| 1148 | ?? null, | 1148 | ?? null, |
| 1149 | workspaceRoot: input.workspaceRoot | 1149 | workspaceRoot: input.workspaceRoot |
| 1150 | ?? runtimeLocalWorkspace?.workspace.workspaceRoot | 1150 | ?? runtimeLocalScope?.scope.scopeRoot |
| 1151 | ?? null, | 1151 | ?? null, |
| 1152 | }; | 1152 | }; |
| 1153 | }); | 1153 | }); |
| @@ -7,7 +7,7 @@ import * as Effect from "effect/Effect"; · 6 unmodified lines | |||
| 7 | 7 | ||
| 8 | import { | 8 | import { |
| 9 | SourceIdSchema, | 9 | SourceIdSchema, |
| 10 | WorkspaceIdSchema, | 10 | ScopeIdSchema, |
| 11 | type Source, | 11 | type Source, |
| 12 | } from "@executor/platform-sdk/schema"; | 12 | } from "@executor/platform-sdk/schema"; |
| 13 | 13 | ||
| @@ -52,7 +52,7 @@ const makeContext = (): Effect.Effect< · 38 unmodified lines | |||
| 52 | 52 | ||
| 53 | const makeSource = (): Source => ({ | 53 | const makeSource = (): Source => ({ |
| 54 | id: SourceIdSchema.make("src_test"), | 54 | id: SourceIdSchema.make("src_test"), |
| 55 | workspaceId: WorkspaceIdSchema.make("ws_test"), | 55 | scopeId: ScopeIdSchema.make("ws_test"), |
| 56 | name: "Test Source", | 56 | name: "Test Source", |
| 57 | kind: "openapi", | 57 | kind: "openapi", |
| 58 | endpoint: "https://example.com/api", | 58 | endpoint: "https://example.com/api", |
| @@ -7,7 +7,7 @@ import * as Effect from "effect/Effect"; · 6 unmodified lines | |||
| 7 | 7 | ||
| 8 | import { | 8 | import { |
| 9 | SourceIdSchema, | 9 | SourceIdSchema, |
| 10 | WorkspaceIdSchema, | 10 | ScopeIdSchema, |
| 11 | type Source, | 11 | type Source, |
| 12 | } from "@executor/platform-sdk/schema"; | 12 | } from "@executor/platform-sdk/schema"; |
| 13 | 13 | ||
| @@ -21,7 +21,6 @@ import { · 7 unmodified lines | |||
| 21 | ExecutableIdSchema, | 21 | ExecutableIdSchema, |
| 22 | ResourceIdSchema, | 22 | ResourceIdSchema, |
| 23 | ResponseSetIdSchema, | 23 | ResponseSetIdSchema, |
| 24 | ScopeIdSchema, | ||
| 25 | ShapeSymbolIdSchema, | 24 | ShapeSymbolIdSchema, |
| 26 | } from "@executor/ir/ids"; | 25 | } from "@executor/ir/ids"; |
| 27 | import type { CatalogV1, ProvenanceRef } from "@executor/ir/model"; | 26 | import type { CatalogV1, ProvenanceRef } from "@executor/ir/model"; |
| @@ -397,7 +396,7 @@ const makeSource = (input: { · 369 unmodified lines | |||
| 397 | status?: Source["status"]; | 396 | status?: Source["status"]; |
| 398 | }): Source => ({ | 397 | }): Source => ({ |
| 399 | id: SourceIdSchema.make(input.id), | 398 | id: SourceIdSchema.make(input.id), |
| 400 | workspaceId: WorkspaceIdSchema.make("ws_test"), | 399 | scopeId: ScopeIdSchema.make("ws_test"), |
| 401 | name: input.id, | 400 | name: input.id, |
| 402 | kind: "graphql", | 401 | kind: "graphql", |
| 403 | endpoint: "https://api.linear.app/graphql", | 402 | endpoint: "https://api.linear.app/graphql", |
| @@ -3,11 +3,11 @@ import { FileSystem } from "@effect/platform"; · 2 unmodified lines | |||
| 3 | import * as Effect from "effect/Effect"; | 3 | import * as Effect from "effect/Effect"; |
| 4 | import * as Schema from "effect/Schema"; | 4 | import * as Schema from "effect/Schema"; |
| 5 | 5 | ||
| 6 | import type { LocalWorkspaceState } from "../../sdk/src/runtime/workspace-state"; | 6 | import type { LocalScopeState } from "../../sdk/src/runtime/scope-state"; |
| 7 | import { | 7 | import { |
| 8 | defaultLocalWorkspaceState, | 8 | defaultLocalScopeState, |
| 9 | LocalWorkspaceStateSchema, | 9 | LocalScopeStateSchema, |
| 10 | } from "../../sdk/src/runtime/workspace-state"; | 10 | } from "../../sdk/src/runtime/scope-state"; |
| 11 | import type { ResolvedLocalWorkspaceContext } from "./config"; | 11 | import type { ResolvedLocalWorkspaceContext } from "./config"; |
| 12 | import { | 12 | import { |
| 13 | LocalFileSystemError, | 13 | LocalFileSystemError, |
| @@ -17,7 +17,7 @@ import { · 3 unmodified lines | |||
| 17 | 17 | ||
| 18 | const WORKSPACE_STATE_BASENAME = "workspace-state.json"; | 18 | const WORKSPACE_STATE_BASENAME = "workspace-state.json"; |
| 19 | 19 | ||
| 20 | const decodeLocalWorkspaceState = Schema.decodeUnknownSync(LocalWorkspaceStateSchema); | 20 | const decodeLocalWorkspaceState = Schema.decodeUnknownSync(LocalScopeStateSchema); |
| 21 | 21 | ||
| 22 | const mapFileSystemError = (path: string, action: string) => (cause: unknown) => | 22 | const mapFileSystemError = (path: string, action: string) => (cause: unknown) => |
| 23 | new LocalFileSystemError({ | 23 | new LocalFileSystemError({ |
| @@ -34,7 +34,7 @@ export const localWorkspaceStatePath = ( · 10 unmodified lines | |||
| 34 | export const loadLocalWorkspaceState = ( | 34 | export const loadLocalWorkspaceState = ( |
| 35 | context: ResolvedLocalWorkspaceContext, | 35 | context: ResolvedLocalWorkspaceContext, |
| 36 | ): Effect.Effect< | 36 | ): Effect.Effect< |
| 37 | LocalWorkspaceState, | 37 | LocalScopeState, |
| 38 | LocalFileSystemError | LocalWorkspaceStateDecodeError, | 38 | LocalFileSystemError | LocalWorkspaceStateDecodeError, |
| 39 | FileSystem.FileSystem | 39 | FileSystem.FileSystem |
| 40 | > => | 40 | > => |
| @@ -45,7 +45,7 @@ export const loadLocalWorkspaceState = ( · 4 unmodified lines | |||
| 45 | Effect.mapError(mapFileSystemError(path, "check workspace state path")), | 45 | Effect.mapError(mapFileSystemError(path, "check workspace state path")), |
| 46 | ); | 46 | ); |
| 47 | if (!exists) { | 47 | if (!exists) { |
| 48 | return defaultLocalWorkspaceState(); | 48 | return defaultLocalScopeState(); |
| 49 | } | 49 | } |
| 50 | 50 | ||
| 51 | const content = yield* fs.readFileString(path, "utf8").pipe( | 51 | const content = yield* fs.readFileString(path, "utf8").pipe( |
| @@ -55,7 +55,7 @@ export const loadLocalWorkspaceState = ( · 3 unmodified lines | |||
| 55 | try: () => decodeLocalWorkspaceState(JSON.parse(content) as unknown), | 55 | try: () => decodeLocalWorkspaceState(JSON.parse(content) as unknown), |
| 56 | catch: (cause) => | 56 | catch: (cause) => |
| 57 | new LocalWorkspaceStateDecodeError({ | 57 | new LocalWorkspaceStateDecodeError({ |
| 58 | message: `Invalid local workspace state at ${path}: ${unknownLocalErrorDetails(cause)}`, | 58 | message: `Invalid local scope state at ${path}: ${unknownLocalErrorDetails(cause)}`, |
| 59 | path, | 59 | path, |
| 60 | details: unknownLocalErrorDetails(cause), | 60 | details: unknownLocalErrorDetails(cause), |
| 61 | }), | 61 | }), |
| @@ -64,7 +64,7 @@ export const loadLocalWorkspaceState = ( · 2 unmodified lines | |||
| 64 | 64 | ||
| 65 | export const writeLocalWorkspaceState = (input: { | 65 | export const writeLocalWorkspaceState = (input: { |
| 66 | context: ResolvedLocalWorkspaceContext; | 66 | context: ResolvedLocalWorkspaceContext; |
| 67 | state: LocalWorkspaceState; | 67 | state: LocalScopeState; |
| 68 | }): Effect.Effect<void, LocalFileSystemError, FileSystem.FileSystem> => | 68 | }): Effect.Effect<void, LocalFileSystemError, FileSystem.FileSystem> => |
| 69 | Effect.gen(function* () { | 69 | Effect.gen(function* () { |
| 70 | const fs = yield* FileSystem.FileSystem; | 70 | const fs = yield* FileSystem.FileSystem; |
| @@ -42,6 +42,7 @@ · 41 unmodified lines | |||
| 42 | }, | 42 | }, |
| 43 | "devDependencies": { | 43 | "devDependencies": { |
| 44 | "@effect/vitest": "catalog:", | 44 | "@effect/vitest": "catalog:", |
| 45 | "@executor/effect-test-utils": "workspace:*", | ||
| 45 | "@modelcontextprotocol/sdk": "^1.26.0", | 46 | "@modelcontextprotocol/sdk": "^1.26.0", |
| 46 | "@types/node": "catalog:", | 47 | "@types/node": "catalog:", |
| 47 | "bun-types": "catalog:", | 48 | "bun-types": "catalog:", |
| @@ -6,8 +6,8 @@ import { · 5 unmodified lines | |||
| 6 | type BoundLocalToolRuntimeLoader, | 6 | type BoundLocalToolRuntimeLoader, |
| 7 | type BoundSourceArtifactStore, | 7 | type BoundSourceArtifactStore, |
| 8 | type BoundSourceTypeDeclarationsRefresher, | 8 | type BoundSourceTypeDeclarationsRefresher, |
| 9 | type BoundWorkspaceConfigStore, | 9 | type BoundScopeConfigStore, |
| 10 | type BoundWorkspaceStateStore, | 10 | type BoundScopeStateStore, |
| 11 | type ExecutorRuntime, | 11 | type ExecutorRuntime, |
| 12 | type ExecutorRuntimeOptions, | 12 | type ExecutorRuntimeOptions, |
| 13 | type RuntimeInstanceConfigService, | 13 | type RuntimeInstanceConfigService, |
| @@ -15,13 +15,13 @@ import { · 1 unmodified line | |||
| 15 | type RuntimeSecretMaterialServices, | 15 | type RuntimeSecretMaterialServices, |
| 16 | } from "./runtime"; | 16 | } from "./runtime"; |
| 17 | import type { | 17 | import type { |
| 18 | ExecutorWorkspaceContext, | 18 | ExecutorScopeContext, |
| 19 | ExecutorWorkspaceDescriptor, | 19 | ExecutorScopeDescriptor, |
| 20 | } from "./workspace"; | 20 | } from "./scope"; |
| 21 | export type { | 21 | export type { |
| 22 | ExecutorWorkspaceContext, | 22 | ExecutorScopeContext, |
| 23 | ExecutorWorkspaceDescriptor, | 23 | ExecutorScopeDescriptor, |
| 24 | } from "./workspace"; | 24 | } from "./scope"; |
| 25 | 25 | ||
| 26 | export type ExecutorBackend = { | 26 | export type ExecutorBackend = { |
| 27 | createRuntime: ( | 27 | createRuntime: ( |
| @@ -30,8 +30,8 @@ export type ExecutorBackend = { · 2 unmodified lines | |||
| 30 | }; | 30 | }; |
| 31 | 31 | ||
| 32 | export type ExecutorInstallationBackend = BoundInstallationStore; | 32 | export type ExecutorInstallationBackend = BoundInstallationStore; |
| 33 | export type ExecutorWorkspaceConfigBackend = BoundWorkspaceConfigStore; | 33 | export type ExecutorScopeConfigBackend = BoundScopeConfigStore; |
| 34 | export type ExecutorWorkspaceStateBackend = BoundWorkspaceStateStore; | 34 | export type ExecutorScopeStateBackend = BoundScopeStateStore; |
| 35 | export type ExecutorSourceArtifactBackend = BoundSourceArtifactStore; | 35 | export type ExecutorSourceArtifactBackend = BoundSourceArtifactStore; |
| 36 | export type ExecutorStateBackend = import("./runtime").ExecutorStateStoreShape; | 36 | export type ExecutorStateBackend = import("./runtime").ExecutorStateStoreShape; |
| 37 | export type ExecutorLocalToolBackend = BoundLocalToolRuntimeLoader; | 37 | export type ExecutorLocalToolBackend = BoundLocalToolRuntimeLoader; |
| @@ -42,8 +42,8 @@ export type ExecutorInstanceConfigBackend = RuntimeInstanceConfigService; · 4 unmodified lines | |||
| 42 | 42 | ||
| 43 | export type ExecutorStorageBackend = { | 43 | export type ExecutorStorageBackend = { |
| 44 | installation: ExecutorInstallationBackend; | 44 | installation: ExecutorInstallationBackend; |
| 45 | workspaceConfig: ExecutorWorkspaceConfigBackend; | 45 | scopeConfig: ExecutorScopeConfigBackend; |
| 46 | workspaceState: ExecutorWorkspaceStateBackend; | 46 | scopeState: ExecutorScopeStateBackend; |
| 47 | sourceArtifacts: ExecutorSourceArtifactBackend; | 47 | sourceArtifacts: ExecutorSourceArtifactBackend; |
| 48 | executorState: ExecutorStateBackend; | 48 | executorState: ExecutorStateBackend; |
| 49 | secretMaterial: ExecutorSecretMaterialBackend; | 49 | secretMaterial: ExecutorSecretMaterialBackend; |
| @@ -51,7 +51,7 @@ export type ExecutorStorageBackend = { · 1 unmodified line | |||
| 51 | }; | 51 | }; |
| 52 | 52 | ||
| 53 | export type ExecutorBackendServices = { | 53 | export type ExecutorBackendServices = { |
| 54 | workspace: ExecutorWorkspaceDescriptor; | 54 | scope: ExecutorScopeDescriptor; |
| 55 | storage: ExecutorStorageBackend; | 55 | storage: ExecutorStorageBackend; |
| 56 | instanceConfig: ExecutorInstanceConfigBackend; | 56 | instanceConfig: ExecutorInstanceConfigBackend; |
| 57 | localTools?: ExecutorLocalToolBackend; | 57 | localTools?: ExecutorLocalToolBackend; |
| @@ -68,7 +68,7 @@ export const createExecutorBackend = (input: { · 10 unmodified lines | |||
| 68 | createExecutorRuntimeFromServices({ | 68 | createExecutorRuntimeFromServices({ |
| 69 | ...options, | 69 | ...options, |
| 70 | services: { | 70 | services: { |
| 71 | workspace: services.workspace, | 71 | scope: services.scope, |
| 72 | storage: services.storage satisfies RuntimeStorageServices, | 72 | storage: services.storage satisfies RuntimeStorageServices, |
| 73 | localToolRuntimeLoader: services.localTools, | 73 | localToolRuntimeLoader: services.localTools, |
| 74 | sourceTypeDeclarationsRefresher: services.sourceTypeDeclarations, | 74 | sourceTypeDeclarationsRefresher: services.sourceTypeDeclarations, |
| @@ -1,4 +1,6 @@ | |||
| 1 | import { HttpApiSchema } from "@effect/platform"; | 1 | import { |
| 2 | HttpApiSchema, | ||
| 3 | } from "@effect/platform"; | ||
| 2 | import * as Schema from "effect/Schema"; | 4 | import * as Schema from "effect/Schema"; |
| 3 | 5 | ||
| 4 | export class ControlPlaneBadRequestError extends Schema.TaggedError<ControlPlaneBadRequestError>()( | 6 | export class ControlPlaneBadRequestError extends Schema.TaggedError<ControlPlaneBadRequestError>()( |
| @@ -1,6 +1,8 @@ | |||
| 1 | import * as Schema from "effect/Schema"; | 1 | import * as Schema from "effect/Schema"; |
| 2 | 2 | ||
| 3 | import { TrimmedNonEmptyStringSchema } from "../string-schemas"; | 3 | import { |
| 4 | TrimmedNonEmptyStringSchema, | ||
| 5 | } from "../string-schemas"; | ||
| 4 | 6 | ||
| 5 | export const CreateExecutionPayloadSchema = Schema.Struct({ | 7 | export const CreateExecutionPayloadSchema = Schema.Struct({ |
| 6 | code: TrimmedNonEmptyStringSchema, | 8 | code: TrimmedNonEmptyStringSchema, |
| @@ -0,0 +1,453 @@ | |||
| 1 | import { join } from "node:path"; | ||
| 2 | import { | ||
| 3 | HttpApi, | ||
| 4 | HttpApiEndpoint, | ||
| 5 | HttpApiGroup, | ||
| 6 | HttpApiSchema, | ||
| 7 | HttpApiBuilder, | ||
| 8 | HttpApiClient, | ||
| 9 | FileSystem, | ||
| 10 | } from "@effect/platform"; | ||
| 11 | import { | ||
| 12 | NodeFileSystem, | ||
| 13 | NodeHttpServer, | ||
| 14 | } from "@effect/platform-node"; | ||
| 15 | import { | ||
| 16 | describe, | ||
| 17 | expect, | ||
| 18 | it, | ||
| 19 | } from "@effect/vitest"; | ||
| 20 | import * as Either from "effect/Either"; | ||
| 21 | import { | ||
| 22 | assertInclude, | ||
| 23 | } from "@effect/vitest/utils"; | ||
| 24 | import * as Effect from "effect/Effect"; | ||
| 25 | import * as Layer from "effect/Layer"; | ||
| 26 | import * as Schema from "effect/Schema"; | ||
| 27 | import { | ||
| 28 | makeOpenApiTestServer, | ||
| 29 | } from "@executor/effect-test-utils"; | ||
| 30 | |||
| 31 | import { | ||
| 32 | createExecutorBackend, | ||
| 33 | createExecutorEffect, | ||
| 34 | type Executor, | ||
| 35 | } from "./index"; | ||
| 36 | import { | ||
| 37 | type LocalInstallation, | ||
| 38 | ScopeIdSchema, | ||
| 39 | } from "./schema"; | ||
| 40 | import { | ||
| 41 | createLocalExecutorServicesEffect, | ||
| 42 | } from "../../sdk-file/src/index"; | ||
| 43 | import { | ||
| 44 | ExecutorApi, | ||
| 45 | createExecutorApiLayer, | ||
| 46 | } from "../../api/src/index"; | ||
| 47 | |||
| 48 | type LocalExecutorServices = Effect.Effect.Success< | ||
| 49 | ReturnType<typeof createLocalExecutorServicesEffect> | ||
| 50 | >; | ||
| 51 | |||
| 52 | const createClientLayer = (executor: Executor) => | ||
| 53 | HttpApiBuilder.serve().pipe( | ||
| 54 | Layer.provide(createExecutorApiLayer(executor)), | ||
| 55 | Layer.provideMerge(NodeHttpServer.layerTest), | ||
| 56 | ); | ||
| 57 | |||
| 58 | const createExecutorApiClient = () => | ||
| 59 | HttpApiClient.make(ExecutorApi, { | ||
| 60 | }); | ||
| 61 | |||
| 62 | type ExecutorApiClient = Effect.Effect.Success< | ||
| 63 | ReturnType<typeof createExecutorApiClient> | ||
| 64 | >; | ||
| 65 | |||
| 66 | const withExecutorApiClient = <A, E>( | ||
| 67 | executor: Executor, | ||
| 68 | f: (client: ExecutorApiClient) => Effect.Effect<A, E, never>, | ||
| 69 | ): Effect.Effect<A, E, never> => | ||
| 70 | Effect.gen(function* () { | ||
| 71 | const client = yield* createExecutorApiClient(); | ||
| 72 | return yield* f(client); | ||
| 73 | }).pipe(Effect.provide(createClientLayer(executor).pipe(Layer.orDie))); | ||
| 74 | |||
| 75 | const expectLeft = <A, E>(effect: Effect.Effect<A, E, never>) => | ||
| 76 | Effect.either(effect).pipe( | ||
| 77 | Effect.flatMap((result) => | ||
| 78 | Either.isLeft(result) | ||
| 79 | ? Effect.succeed(result.left) | ||
| 80 | : Effect.die("Expected effect to fail"), | ||
| 81 | ), | ||
| 82 | ); | ||
| 83 | |||
| 84 | type OpenApiSpecServer = { | ||
| 85 | baseUrl: string; | ||
| 86 | specUrl: string; | ||
| 87 | close: () => Promise<void>; | ||
| 88 | }; | ||
| 89 | |||
| 90 | const ownerParam = HttpApiSchema.param("owner", Schema.String); | ||
| 91 | const repoParam = HttpApiSchema.param("repo", Schema.String); | ||
| 92 | const issueIdParam = HttpApiSchema.param("issueId", Schema.String); | ||
| 93 | |||
| 94 | class WorkspaceSourceReposApi extends HttpApiGroup.make("repos") | ||
| 95 | .add( | ||
| 96 | HttpApiEndpoint.get("getRepo")`/repos/${ownerParam}/${repoParam}` | ||
| 97 | .addSuccess(Schema.Unknown), | ||
| 98 | ) | ||
| 99 | {} | ||
| 100 | |||
| 101 | class WorkspaceSourceIssuesApi extends HttpApiGroup.make("issues") | ||
| 102 | .add( | ||
| 103 | HttpApiEndpoint.get("getIssue")`/issues/${issueIdParam}` | ||
| 104 | .addSuccess(Schema.Unknown), | ||
| 105 | ) | ||
| 106 | .add( | ||
| 107 | HttpApiEndpoint.get("listIssues")`/issues` | ||
| 108 | .addSuccess(Schema.Unknown), | ||
| 109 | ) | ||
| 110 | {} | ||
| 111 | |||
| 112 | class WorkspaceSourceReposRootApi extends HttpApi.make("workspaceSourceRepos") | ||
| 113 | .add(WorkspaceSourceReposApi) | ||
| 114 | {} | ||
| 115 | |||
| 116 | class WorkspaceSourceIssuesRootApi extends HttpApi.make("workspaceSourceIssues") | ||
| 117 | .add(WorkspaceSourceIssuesApi) | ||
| 118 | {} | ||
| 119 | |||
| 120 | const workspaceSourceReposLive = HttpApiBuilder.group( | ||
| 121 | WorkspaceSourceReposRootApi, | ||
| 122 | "repos", | ||
| 123 | (handlers) => | ||
| 124 | handlers.handle("getRepo", ({ path }) => | ||
| 125 | Effect.succeed({ | ||
| 126 | full_name: `${path.owner}/${path.repo}`, | ||
| 127 | private: false, | ||
| 128 | }), | ||
| 129 | ), | ||
| 130 | ); | ||
| 131 | |||
| 132 | const workspaceSourceIssuesLive = HttpApiBuilder.group( | ||
| 133 | WorkspaceSourceIssuesRootApi, | ||
| 134 | "issues", | ||
| 135 | (handlers) => | ||
| 136 | handlers | ||
| 137 | .handle("getIssue", ({ path }) => | ||
| 138 | Effect.succeed({ | ||
| 139 | id: path.issueId, | ||
| 140 | title: `Issue ${path.issueId}`, | ||
| 141 | }), | ||
| 142 | ) | ||
| 143 | .handle("listIssues", () => | ||
| 144 | Effect.succeed([ | ||
| 145 | { | ||
| 146 | id: "1", | ||
| 147 | title: "Issue 1", | ||
| 148 | }, | ||
| 149 | ]), | ||
| 150 | ), | ||
| 151 | ); | ||
| 152 | |||
| 153 | const workspaceSourceReposApiLayer = HttpApiBuilder.api( | ||
| 154 | WorkspaceSourceReposRootApi, | ||
| 155 | ).pipe(Layer.provide(workspaceSourceReposLive)); | ||
| 156 | |||
| 157 | const workspaceSourceIssuesApiLayer = HttpApiBuilder.api( | ||
| 158 | WorkspaceSourceIssuesRootApi, | ||
| 159 | ).pipe(Layer.provide(workspaceSourceIssuesLive)); | ||
| 160 | |||
| 161 | const createScopedExecutor = (input: { | ||
| 162 | services: LocalExecutorServices; | ||
| 163 | installation: LocalInstallation; | ||
| 164 | }) => | ||
| 165 | createExecutorEffect({ | ||
| 166 | backend: createExecutorBackend({ | ||
| 167 | loadServices: () => | ||
| 168 | Effect.succeed({ | ||
| 169 | ...input.services, | ||
| 170 | scope: { | ||
| 171 | ...input.services.scope, | ||
| 172 | actorScopeId: input.installation.actorScopeId, | ||
| 173 | resolutionScopeIds: input.installation.resolutionScopeIds, | ||
| 174 | }, | ||
| 175 | storage: { | ||
| 176 | ...input.services.storage, | ||
| 177 | installation: { | ||
| 178 | load: () => Effect.succeed(input.installation), | ||
| 179 | getOrProvision: () => Effect.succeed(input.installation), | ||
| 180 | }, | ||
| 181 | }, | ||
| 182 | }), | ||
| 183 | }), | ||
| 184 | getLocalServerBaseUrl: () => "http://127.0.0.1", | ||
| 185 | }); | ||
| 186 | |||
| 187 | const makeSharedScopeExecutors = Effect.acquireRelease( | ||
| 188 | Effect.gen(function* () { | ||
| 189 | const fs = yield* FileSystem.FileSystem; | ||
| 190 | const sharedScopeId = ScopeIdSchema.make("org_shared_sdk_pair_test"); | ||
| 191 | |||
| 192 | const workspaceRootA = yield* fs.makeTempDirectoryScoped({ | ||
| 193 | prefix: "executor-sdk-scope-a-", | ||
| 194 | }); | ||
| 195 | const workspaceRootB = yield* fs.makeTempDirectoryScoped({ | ||
| 196 | prefix: "executor-sdk-scope-b-", | ||
| 197 | }); | ||
| 198 | |||
| 199 | const servicesA = yield* createLocalExecutorServicesEffect({ | ||
| 200 | workspaceRoot: workspaceRootA, | ||
| 201 | homeConfigPath: join(workspaceRootA, ".executor-home.jsonc"), | ||
| 202 | homeStateDirectory: join(workspaceRootA, ".executor-home-state"), | ||
| 203 | }); | ||
| 204 | const servicesB = yield* createLocalExecutorServicesEffect({ | ||
| 205 | workspaceRoot: workspaceRootB, | ||
| 206 | homeConfigPath: join(workspaceRootB, ".executor-home.jsonc"), | ||
| 207 | homeStateDirectory: join(workspaceRootB, ".executor-home-state"), | ||
| 208 | }); | ||
| 209 | |||
| 210 | const baseInstallationA = | ||
| 211 | yield* servicesA.storage.installation.getOrProvision(); | ||
| 212 | const baseInstallationB = | ||
| 213 | yield* servicesB.storage.installation.getOrProvision(); | ||
| 214 | |||
| 215 | const sharedStorageClose = (() => { | ||
| 216 | let closed = false; | ||
| 217 | return async () => { | ||
| 218 | if (closed) { | ||
| 219 | return; | ||
| 220 | } | ||
| 221 | closed = true; | ||
| 222 | await servicesA.storage.close?.(); | ||
| 223 | await servicesB.storage.close?.(); | ||
| 224 | }; | ||
| 225 | })(); | ||
| 226 | |||
| 227 | const sharedStorage = { | ||
| 228 | executorState: servicesA.storage.executorState, | ||
| 229 | secretMaterial: servicesA.storage.secretMaterial, | ||
| 230 | close: sharedStorageClose, | ||
| 231 | }; | ||
| 232 | |||
| 233 | const installationA: LocalInstallation = { | ||
| 234 | ...baseInstallationA, | ||
| 235 | actorScopeId: ScopeIdSchema.make("acc_sdk_executor_a"), | ||
| 236 | resolutionScopeIds: [ | ||
| 237 | baseInstallationA.scopeId, | ||
| 238 | sharedScopeId, | ||
| 239 | ScopeIdSchema.make("acc_sdk_executor_a"), | ||
| 240 | ], | ||
| 241 | }; | ||
| 242 | const installationB: LocalInstallation = { | ||
| 243 | ...baseInstallationB, | ||
| 244 | actorScopeId: ScopeIdSchema.make("acc_sdk_executor_b"), | ||
| 245 | resolutionScopeIds: [ | ||
| 246 | baseInstallationB.scopeId, | ||
| 247 | sharedScopeId, | ||
| 248 | ScopeIdSchema.make("acc_sdk_executor_b"), | ||
| 249 | ], | ||
| 250 | }; | ||
| 251 | |||
| 252 | const executorA = yield* createScopedExecutor({ | ||
| 253 | services: { | ||
| 254 | ...servicesA, | ||
| 255 | storage: { | ||
| 256 | ...servicesA.storage, | ||
| 257 | ...sharedStorage, | ||
| 258 | }, | ||
| 259 | }, | ||
| 260 | installation: installationA, | ||
| 261 | }); | ||
| 262 | const executorB = yield* createScopedExecutor({ | ||
| 263 | services: { | ||
| 264 | ...servicesB, | ||
| 265 | storage: { | ||
| 266 | ...servicesB.storage, | ||
| 267 | ...sharedStorage, | ||
| 268 | }, | ||
| 269 | }, | ||
| 270 | installation: installationB, | ||
| 271 | }); | ||
| 272 | |||
| 273 | return { | ||
| 274 | executorA, | ||
| 275 | executorB, | ||
| 276 | sharedScopeId, | ||
| 277 | }; | ||
| 278 | }).pipe(Effect.provide(NodeFileSystem.layer)), | ||
| 279 | ({ executorA, executorB }) => | ||
| 280 | Effect.promise(async () => { | ||
| 281 | await executorA.close(); | ||
| 282 | await executorB.close(); | ||
| 283 | }).pipe(Effect.orDie), | ||
| 284 | ); | ||
| 285 | |||
| 286 | describe("executor", () => { | ||
| 287 | it.scoped( | ||
| 288 | "keeps workspace sources isolated across executors that share an ancestor scope", | ||
| 289 | () => | ||
| 290 | Effect.gen(function* () { | ||
| 291 | const { executorA, executorB, sharedScopeId } = | ||
| 292 | yield* makeSharedScopeExecutors; | ||
| 293 | const openApiServer: OpenApiSpecServer = yield* makeOpenApiTestServer({ | ||
| 294 | apiLayer: workspaceSourceReposApiLayer, | ||
| 295 | }); | ||
| 296 | |||
| 297 | expect(executorA.resolutionScopeIds).toContain(sharedScopeId); | ||
| 298 | expect(executorB.resolutionScopeIds).toContain(sharedScopeId); | ||
| 299 | |||
| 300 | const sourceA = yield* withExecutorApiClient(executorA, (client) => | ||
| 301 | client.sources.create({ | ||
| 302 | path: { | ||
| 303 | workspaceId: executorA.scopeId, | ||
| 304 | }, | ||
| 305 | payload: { | ||
| 306 | name: "Workspace A Source", | ||
| 307 | kind: "openapi", | ||
| 308 | endpoint: openApiServer.baseUrl, | ||
| 309 | namespace: "workspace.a", | ||
| 310 | binding: { | ||
| 311 | specUrl: openApiServer.specUrl, | ||
| 312 | defaultHeaders: null, | ||
| 313 | }, | ||
| 314 | auth: { kind: "none" }, | ||
| 315 | }, | ||
| 316 | }), | ||
| 317 | ); | ||
| 318 | const sourceB = yield* withExecutorApiClient(executorB, (client) => | ||
| 319 | client.sources.create({ | ||
| 320 | path: { | ||
| 321 | workspaceId: executorB.scopeId, | ||
| 322 | }, | ||
| 323 | payload: { | ||
| 324 | name: "Workspace B Source", | ||
| 325 | kind: "openapi", | ||
| 326 | endpoint: openApiServer.baseUrl, | ||
| 327 | namespace: "workspace.b", | ||
| 328 | binding: { | ||
| 329 | specUrl: openApiServer.specUrl, | ||
| 330 | defaultHeaders: null, | ||
| 331 | }, | ||
| 332 | auth: { kind: "none" }, | ||
| 333 | }, | ||
| 334 | }), | ||
| 335 | ); | ||
| 336 | |||
| 337 | const listedA = yield* withExecutorApiClient(executorA, (client) => | ||
| 338 | client.sources.list({ | ||
| 339 | path: { | ||
| 340 | workspaceId: executorA.scopeId, | ||
| 341 | }, | ||
| 342 | }), | ||
| 343 | ); | ||
| 344 | const listedB = yield* withExecutorApiClient(executorB, (client) => | ||
| 345 | client.sources.list({ | ||
| 346 | path: { | ||
| 347 | workspaceId: executorB.scopeId, | ||
| 348 | }, | ||
| 349 | }), | ||
| 350 | ); | ||
| 351 | |||
| 352 | expect(listedA.map((source) => source.id)).toEqual([sourceA.id]); | ||
| 353 | expect(listedB.map((source) => source.id)).toEqual([sourceB.id]); | ||
| 354 | |||
| 355 | const lookupFromSibling = yield* expectLeft( | ||
| 356 | withExecutorApiClient(executorB, (client) => | ||
| 357 | client.sources.get({ | ||
| 358 | path: { | ||
| 359 | workspaceId: executorB.scopeId, | ||
| 360 | sourceId: sourceA.id, | ||
| 361 | }, | ||
| 362 | }), | ||
| 363 | ), | ||
| 364 | ); | ||
| 365 | assertInclude(String(lookupFromSibling), "Source not found"); | ||
| 366 | }), | ||
| 367 | ); | ||
| 368 | |||
| 369 | it.scoped( | ||
| 370 | "keeps each executor's tool surface tied to its own workspace sources", | ||
| 371 | () => | ||
| 372 | Effect.gen(function* () { | ||
| 373 | const { executorA, executorB } = | ||
| 374 | yield* makeSharedScopeExecutors; | ||
| 375 | const openApiServerA: OpenApiSpecServer = yield* makeOpenApiTestServer({ | ||
| 376 | apiLayer: workspaceSourceReposApiLayer, | ||
| 377 | }); | ||
| 378 | const openApiServerB: OpenApiSpecServer = yield* makeOpenApiTestServer({ | ||
| 379 | apiLayer: workspaceSourceIssuesApiLayer, | ||
| 380 | }); | ||
| 381 | |||
| 382 | const sourceA = yield* withExecutorApiClient(executorA, (client) => | ||
| 383 | client.sources.create({ | ||
| 384 | path: { | ||
| 385 | workspaceId: executorA.scopeId, | ||
| 386 | }, | ||
| 387 | payload: { | ||
| 388 | name: "Workspace A Tools", | ||
| 389 | kind: "openapi", | ||
| 390 | endpoint: openApiServerA.baseUrl, | ||
| 391 | namespace: "workspace.a", | ||
| 392 | binding: { | ||
| 393 | specUrl: openApiServerA.specUrl, | ||
| 394 | defaultHeaders: null, | ||
| 395 | }, | ||
| 396 | auth: { kind: "none" }, | ||
| 397 | }, | ||
| 398 | }), | ||
| 399 | ); | ||
| 400 | const sourceB = yield* withExecutorApiClient(executorB, (client) => | ||
| 401 | client.sources.create({ | ||
| 402 | path: { | ||
| 403 | workspaceId: executorB.scopeId, | ||
| 404 | }, | ||
| 405 | payload: { | ||
| 406 | name: "Workspace B Tools", | ||
| 407 | kind: "openapi", | ||
| 408 | endpoint: openApiServerB.baseUrl, | ||
| 409 | namespace: "workspace.b", | ||
| 410 | binding: { | ||
| 411 | specUrl: openApiServerB.specUrl, | ||
| 412 | defaultHeaders: null, | ||
| 413 | }, | ||
| 414 | auth: { kind: "none" }, | ||
| 415 | }, | ||
| 416 | }), | ||
| 417 | ); | ||
| 418 | |||
| 419 | const inspectionA = yield* withExecutorApiClient(executorA, (client) => | ||
| 420 | client.sources.inspection({ | ||
| 421 | path: { | ||
| 422 | workspaceId: executorA.scopeId, | ||
| 423 | sourceId: sourceA.id, | ||
| 424 | }, | ||
| 425 | }), | ||
| 426 | ); | ||
| 427 | const inspectionB = yield* withExecutorApiClient(executorB, (client) => | ||
| 428 | client.sources.inspection({ | ||
| 429 | path: { | ||
| 430 | workspaceId: executorB.scopeId, | ||
| 431 | sourceId: sourceB.id, | ||
| 432 | }, | ||
| 433 | }), | ||
| 434 | ); | ||
| 435 | |||
| 436 | expect(inspectionA.toolCount).toBe(1); | ||
| 437 | expect(inspectionB.toolCount).toBe(2); | ||
| 438 | |||
| 439 | const siblingInspection = yield* expectLeft( | ||
| 440 | withExecutorApiClient(executorA, (client) => | ||
| 441 | client.sources.inspection({ | ||
| 442 | path: { | ||
| 443 | workspaceId: executorA.scopeId, | ||
| 444 | sourceId: sourceB.id, | ||
| 445 | }, | ||
| 446 | }), | ||
| 447 | ), | ||
| 448 | ); | ||
| 449 | assertInclude(String(siblingInspection), "Source not found"); | ||
| 450 | }), | ||
| 451 | 60_000, | ||
| 452 | ); | ||
| 453 | }); | ||
| @@ -1,19 +1,23 @@ | |||
| 1 | import * as Effect from "effect/Effect"; | 1 | import * as Effect from "effect/Effect"; |
| 2 | 2 | ||
| 3 | import type { | 3 | import type { |
| 4 | AccountId, | 4 | ScopeId, |
| 5 | Execution, | 5 | Execution, |
| 6 | ExecutionEnvelope, | 6 | ExecutionEnvelope, |
| 7 | ExecutionInteraction, | 7 | ExecutionInteraction, |
| 8 | LocalInstallation, | 8 | LocalInstallation, |
| 9 | LocalWorkspacePolicy, | 9 | LocalScopePolicy, |
| 10 | ProviderAuthGrant, | 10 | ProviderAuthGrant, |
| 11 | Source, | 11 | Source, |
| 12 | WorkspaceId, | 12 | ScopeOauthClient, |
| 13 | WorkspaceOauthClient, | 13 | } from "./schema"; |
| 14 | import { | ||
| 15 | ExecutionIdSchema, | ||
| 14 | } from "./schema"; | 16 | } from "./schema"; |
| 15 | import { ExecutionIdSchema } from "./schema"; | 17 | import type { |
| 16 | import type { CreateExecutionPayload, ResumeExecutionPayload } from "./executions/contracts"; | 18 | CreateExecutionPayload, |
| 19 | ResumeExecutionPayload, | ||
| 20 | } from "./executions/contracts"; | ||
| 17 | import type { | 21 | import type { |
| 18 | CreateSecretPayload, | 22 | CreateSecretPayload, |
| 19 | CreateSecretResult, | 23 | CreateSecretResult, |
| @@ -36,7 +40,10 @@ import { · 16 unmodified lines | |||
| 36 | listLocalSecrets, | 40 | listLocalSecrets, |
| 37 | updateLocalSecret, | 41 | updateLocalSecret, |
| 38 | } from "./local/secrets"; | 42 | } from "./local/secrets"; |
| 39 | import type { CreatePolicyPayload, UpdatePolicyPayload } from "./policies/contracts"; | 43 | import type { |
| 44 | CreatePolicyPayload, | ||
| 45 | UpdatePolicyPayload, | ||
| 46 | } from "./policies/contracts"; | ||
| 40 | import { | 47 | import { |
| 41 | createPolicy, | 48 | createPolicy, |
| 42 | getPolicy, | 49 | getPolicy, |
| @@ -46,10 +53,12 @@ import { · 3 unmodified lines | |||
| 46 | } from "./policies/operations"; | 53 | } from "./policies/operations"; |
| 47 | import type { | 54 | import type { |
| 48 | CreateSourcePayload, | 55 | CreateSourcePayload, |
| 49 | CreateWorkspaceOauthClientPayload, | 56 | CreateScopeOauthClientPayload, |
| 50 | UpdateSourcePayload, | 57 | UpdateSourcePayload, |
| 51 | } from "./sources/contracts"; | 58 | } from "./sources/contracts"; |
| 52 | import { discoverSource } from "./sources/discovery"; | 59 | import { |
| 60 | discoverSource, | ||
| 61 | } from "./sources/discovery"; | ||
| 53 | import { | 62 | import { |
| 54 | discoverSourceInspectionTools, | 63 | discoverSourceInspectionTools, |
| 55 | getSourceInspection, | 64 | getSourceInspection, |
| @@ -62,17 +71,23 @@ import { · 6 unmodified lines | |||
| 62 | removeSource, | 71 | removeSource, |
| 63 | updateSource, | 72 | updateSource, |
| 64 | } from "./sources/operations"; | 73 | } from "./sources/operations"; |
| 65 | import type { ExecutorBackend } from "./backend"; | 74 | import type { |
| 75 | ExecutorBackend, | ||
| 76 | } from "./backend"; | ||
| 66 | import { | 77 | import { |
| 67 | provideExecutorRuntime, | 78 | provideExecutorRuntime, |
| 68 | type ExecutorRuntime, | 79 | type ExecutorRuntime, |
| 69 | type ExecutorRuntimeOptions, | 80 | type ExecutorRuntimeOptions, |
| 70 | type CreateWorkspaceInternalToolMap, | 81 | type CreateScopeInternalToolMap, |
| 71 | type ResolveExecutionEnvironment, | 82 | type ResolveExecutionEnvironment, |
| 72 | type ResolveSecretMaterial, | 83 | type ResolveSecretMaterial, |
| 73 | RuntimeSourceAuthServiceTag, | 84 | RuntimeSourceAuthServiceTag, |
| 74 | } from "./runtime"; | 85 | } from "./runtime"; |
| 75 | import { createExecution, getExecution, resumeExecution } from "./runtime/execution/service"; | 86 | import { |
| 87 | createExecution, | ||
| 88 | getExecution, | ||
| 89 | resumeExecution, | ||
| 90 | } from "./runtime/execution/service"; | ||
| 76 | import type { | 91 | import type { |
| 77 | CompleteProviderOauthCallbackResult, | 92 | CompleteProviderOauthCallbackResult, |
| 78 | CompleteSourceCredentialSetupResult, | 93 | CompleteSourceCredentialSetupResult, |
| @@ -96,29 +111,30 @@ type ProvidedEffect<T extends Effect.Effect<any, any, any>> = Effect.Effect< · 17 unmodified lines | |||
| 96 | 111 | ||
| 97 | export type ExecutorSourceInput = DistributiveOmit< | 112 | export type ExecutorSourceInput = DistributiveOmit< |
| 98 | ExecutorAddSourceInput, | 113 | ExecutorAddSourceInput, |
| 99 | "workspaceId" | "actorAccountId" | "executionId" | "interactionId" | 114 | "scopeId" | "actorScopeId" | "executionId" | "interactionId" |
| 100 | >; | 115 | >; |
| 101 | 116 | ||
| 102 | export type ExecutorSourceBatchInput = DistributiveOmit< | 117 | export type ExecutorSourceBatchInput = DistributiveOmit< |
| 103 | ConnectGoogleDiscoveryBatchInput, | 118 | ConnectGoogleDiscoveryBatchInput, |
| 104 | "workspaceId" | "actorAccountId" | "executionId" | "interactionId" | 119 | "scopeId" | "actorScopeId" | "executionId" | "interactionId" |
| 105 | >; | 120 | >; |
| 106 | 121 | ||
| 107 | export type ExecutorMcpSourceInput = DistributiveOmit< | 122 | export type ExecutorMcpSourceInput = DistributiveOmit< |
| 108 | ConnectMcpSourceInput, | 123 | ConnectMcpSourceInput, |
| 109 | "workspaceId" | "actorAccountId" | 124 | "scopeId" | "actorScopeId" |
| 110 | >; | 125 | >; |
| 111 | 126 | ||
| 112 | export type ExecutorSourceOAuthInput = DistributiveOmit< | 127 | export type ExecutorSourceOAuthInput = DistributiveOmit< |
| 113 | StartSourceOAuthSessionInput, | 128 | StartSourceOAuthSessionInput, |
| 114 | "workspaceId" | "actorAccountId" | 129 | "scopeId" | "actorScopeId" |
| 115 | >; | 130 | >; |
| 116 | 131 | ||
| 117 | export type Executor = { | 132 | export type Executor = { |
| 118 | runtime: ExecutorRuntime; | 133 | runtime: ExecutorRuntime; |
| 119 | installation: LocalInstallation; | 134 | installation: LocalInstallation; |
| 120 | workspaceId: WorkspaceId; | 135 | scopeId: ScopeId; |
| 121 | accountId: AccountId; | 136 | actorScopeId: ScopeId; |
| 137 | resolutionScopeIds: ReadonlyArray<ScopeId>; | ||
| 122 | provide: <A, E, R>(effect: Effect.Effect<A, E, R>) => Effect.Effect<A, E, any>; | 138 | provide: <A, E, R>(effect: Effect.Effect<A, E, R>) => Effect.Effect<A, E, any>; |
| 123 | run: <A, E, R>(effect: Effect.Effect<A, E, R>) => Promise<A>; | 139 | run: <A, E, R>(effect: Effect.Effect<A, E, R>) => Promise<A>; |
| 124 | close: () => Promise<void>; | 140 | close: () => Promise<void>; |
| @@ -202,12 +218,12 @@ export type Executor = { · 77 unmodified lines | |||
| 202 | oauthClients: { | 218 | oauthClients: { |
| 203 | list: ( | 219 | list: ( |
| 204 | providerKey: string, | 220 | providerKey: string, |
| 205 | ) => Effect.Effect<ReadonlyArray<WorkspaceOauthClient>, Error, never>; | 221 | ) => Effect.Effect<ReadonlyArray<ScopeOauthClient>, Error, never>; |
| 206 | create: ( | 222 | create: ( |
| 207 | payload: CreateWorkspaceOauthClientPayload, | 223 | payload: CreateScopeOauthClientPayload, |
| 208 | ) => Effect.Effect<WorkspaceOauthClient, Error, never>; | 224 | ) => Effect.Effect<ScopeOauthClient, Error, never>; |
| 209 | remove: ( | 225 | remove: ( |
| 210 | oauthClientId: WorkspaceOauthClient["id"], | 226 | oauthClientId: ScopeOauthClient["id"], |
| 211 | ) => Effect.Effect<boolean, Error, never>; | 227 | ) => Effect.Effect<boolean, Error, never>; |
| 212 | }; | 228 | }; |
| 213 | providerGrants: { | 229 | providerGrants: { |
| @@ -225,8 +241,8 @@ export type Executor = { · 11 unmodified lines | |||
| 225 | errorDescription?: string | null; | 241 | errorDescription?: string | null; |
| 226 | }) => Effect.Effect<CompleteSourceOAuthSessionResult, Error, never>; | 242 | }) => Effect.Effect<CompleteSourceOAuthSessionResult, Error, never>; |
| 227 | completeProviderCallback: (input: { | 243 | completeProviderCallback: (input: { |
| 228 | workspaceId?: WorkspaceId; | 244 | scopeId?: ScopeId; |
| 229 | actorAccountId?: AccountId | null; | 245 | actorScopeId?: ScopeId | null; |
| 230 | state: string; | 246 | state: string; |
| 231 | code?: string | null; | 247 | code?: string | null; |
| 232 | error?: string | null; | 248 | error?: string | null; |
| @@ -275,13 +291,13 @@ export type Executor = { · 42 unmodified lines | |||
| 275 | remove: (secretId: string) => Promise<DeleteSecretResult>; | 291 | remove: (secretId: string) => Promise<DeleteSecretResult>; |
| 276 | }; | 292 | }; |
| 277 | policies: { | 293 | policies: { |
| 278 | list: () => Promise<ReadonlyArray<LocalWorkspacePolicy>>; | 294 | list: () => Promise<ReadonlyArray<LocalScopePolicy>>; |
| 279 | create: (payload: CreatePolicyPayload) => Promise<LocalWorkspacePolicy>; | 295 | create: (payload: CreatePolicyPayload) => Promise<LocalScopePolicy>; |
| 280 | get: (policyId: string) => Promise<LocalWorkspacePolicy>; | 296 | get: (policyId: string) => Promise<LocalScopePolicy>; |
| 281 | update: ( | 297 | update: ( |
| 282 | policyId: string, | 298 | policyId: string, |
| 283 | payload: UpdatePolicyPayload, | 299 | payload: UpdatePolicyPayload, |
| 284 | ) => Promise<LocalWorkspacePolicy>; | 300 | ) => Promise<LocalScopePolicy>; |
| 285 | remove: (policyId: string) => Promise<boolean>; | 301 | remove: (policyId: string) => Promise<boolean>; |
| 286 | }; | 302 | }; |
| 287 | sources: { | 303 | sources: { |
| @@ -314,11 +330,11 @@ export type Executor = { · 26 unmodified lines | |||
| 314 | }) => Promise<Effect.Effect.Success<ReturnType<typeof discoverSourceInspectionTools>>>; | 330 | }) => Promise<Effect.Effect.Success<ReturnType<typeof discoverSourceInspectionTools>>>; |
| 315 | }; | 331 | }; |
| 316 | oauthClients: { | 332 | oauthClients: { |
| 317 | list: (providerKey: string) => Promise<ReadonlyArray<WorkspaceOauthClient>>; | 333 | list: (providerKey: string) => Promise<ReadonlyArray<ScopeOauthClient>>; |
| 318 | create: ( | 334 | create: ( |
| 319 | payload: CreateWorkspaceOauthClientPayload, | 335 | payload: CreateScopeOauthClientPayload, |
| 320 | ) => Promise<WorkspaceOauthClient>; | 336 | ) => Promise<ScopeOauthClient>; |
| 321 | remove: (oauthClientId: WorkspaceOauthClient["id"]) => Promise<boolean>; | 337 | remove: (oauthClientId: ScopeOauthClient["id"]) => Promise<boolean>; |
| 322 | }; | 338 | }; |
| 323 | providerGrants: { | 339 | providerGrants: { |
| 324 | remove: (grantId: ProviderAuthGrant["id"]) => Promise<boolean>; | 340 | remove: (grantId: ProviderAuthGrant["id"]) => Promise<boolean>; |
| @@ -333,8 +349,8 @@ export type Executor = { · 8 unmodified lines | |||
| 333 | errorDescription?: string | null; | 349 | errorDescription?: string | null; |
| 334 | }) => Promise<CompleteSourceOAuthSessionResult>; | 350 | }) => Promise<CompleteSourceOAuthSessionResult>; |
| 335 | completeProviderCallback: (input: { | 351 | completeProviderCallback: (input: { |
| 336 | workspaceId?: WorkspaceId; | 352 | scopeId?: ScopeId; |
| 337 | actorAccountId?: AccountId | null; | 353 | actorScopeId?: ScopeId | null; |
| 338 | state: string; | 354 | state: string; |
| 339 | code?: string | null; | 355 | code?: string | null; |
| 340 | error?: string | null; | 356 | error?: string | null; |
| @@ -357,8 +373,8 @@ export type CreateExecutorOptions = ExecutorRuntimeOptions & { · 16 unmodified lines | |||
| 357 | 373 | ||
| 358 | const fromRuntime = (runtime: ExecutorRuntime): Executor => { | 374 | const fromRuntime = (runtime: ExecutorRuntime): Executor => { |
| 359 | const installation = runtime.localInstallation; | 375 | const installation = runtime.localInstallation; |
| 360 | const workspaceId = installation.workspaceId; | 376 | const scopeId = installation.scopeId; |
| 361 | const accountId = installation.accountId; | 377 | const actorScopeId = installation.actorScopeId; |
| 362 | const provide = <A, E, R>(effect: Effect.Effect<A, E, R>) => | 378 | const provide = <A, E, R>(effect: Effect.Effect<A, E, R>) => |
| 363 | provideExecutorRuntime(effect, runtime); | 379 | provideExecutorRuntime(effect, runtime); |
| 364 | const run = <A, E, R>(effect: Effect.Effect<A, E, R>) => | 380 | const run = <A, E, R>(effect: Effect.Effect<A, E, R>) => |
| @@ -383,7 +399,7 @@ const fromRuntime = (runtime: ExecutorRuntime): Executor => { · 18 unmodified lines | |||
| 383 | get: ({ sourceId, interactionId }) => | 399 | get: ({ sourceId, interactionId }) => |
| 384 | provide( | 400 | provide( |
| 385 | getSourceCredentialInteraction({ | 401 | getSourceCredentialInteraction({ |
| 386 | workspaceId, | 402 | scopeId, |
| 387 | sourceId, | 403 | sourceId, |
| 388 | interactionId, | 404 | interactionId, |
| 389 | }), | 405 | }), |
| @@ -391,7 +407,7 @@ const fromRuntime = (runtime: ExecutorRuntime): Executor => { · 1 unmodified line | |||
| 391 | submit: ({ sourceId, interactionId, action, token }) => | 407 | submit: ({ sourceId, interactionId, action, token }) => |
| 392 | provide( | 408 | provide( |
| 393 | submitSourceCredentialInteraction({ | 409 | submitSourceCredentialInteraction({ |
| 394 | workspaceId, | 410 | scopeId, |
| 395 | sourceId, | 411 | sourceId, |
| 396 | interactionId, | 412 | interactionId, |
| 397 | action, | 413 | action, |
| @@ -401,7 +417,7 @@ const fromRuntime = (runtime: ExecutorRuntime): Executor => { · 3 unmodified lines | |||
| 401 | complete: ({ sourceId, state, code, error, errorDescription }) => | 417 | complete: ({ sourceId, state, code, error, errorDescription }) => |
| 402 | provide( | 418 | provide( |
| 403 | completeSourceCredentialSetup({ | 419 | completeSourceCredentialSetup({ |
| 404 | workspaceId, | 420 | scopeId, |
| 405 | sourceId, | 421 | sourceId, |
| 406 | state, | 422 | state, |
| 407 | code, | 423 | code, |
| @@ -419,15 +435,15 @@ const fromRuntime = (runtime: ExecutorRuntime): Executor => { · 11 unmodified lines | |||
| 419 | remove: (secretId: string) => provide(deleteLocalSecret(secretId)), | 435 | remove: (secretId: string) => provide(deleteLocalSecret(secretId)), |
| 420 | }, | 436 | }, |
| 421 | policies: { | 437 | policies: { |
| 422 | list: () => provide(listPolicies(workspaceId)), | 438 | list: () => provide(listPolicies(scopeId)), |
| 423 | create: (payload: CreatePolicyPayload) => | 439 | create: (payload: CreatePolicyPayload) => |
| 424 | provide(createPolicy({ workspaceId, payload })), | 440 | provide(createPolicy({ scopeId, payload })), |
| 425 | get: (policyId: string) => | 441 | get: (policyId: string) => |
| 426 | provide(getPolicy({ workspaceId, policyId: policyId as never })), | 442 | provide(getPolicy({ scopeId, policyId: policyId as never })), |
| 427 | update: (policyId: string, payload: UpdatePolicyPayload) => | 443 | update: (policyId: string, payload: UpdatePolicyPayload) => |
| 428 | provide(updatePolicy({ workspaceId, policyId: policyId as never, payload })), | 444 | provide(updatePolicy({ scopeId, policyId: policyId as never, payload })), |
| 429 | remove: (policyId: string) => | 445 | remove: (policyId: string) => |
| 430 | provide(removePolicy({ workspaceId, policyId: policyId as never })), | 446 | provide(removePolicy({ scopeId, policyId: policyId as never })), |
| 431 | }, | 447 | }, |
| 432 | sources: { | 448 | sources: { |
| 433 | add: (input: ExecutorSourceInput, options?: { baseUrl?: string | null }) => | 449 | add: (input: ExecutorSourceInput, options?: { baseUrl?: string | null }) => |
| @@ -436,8 +452,8 @@ const fromRuntime = (runtime: ExecutorRuntime): Executor => { · 2 unmodified lines | |||
| 436 | return service.addExecutorSource( | 452 | return service.addExecutorSource( |
| 437 | { | 453 | { |
| 438 | ...input, | 454 | ...input, |
| 439 | workspaceId, | 455 | scopeId, |
| 440 | actorAccountId: accountId, | 456 | actorScopeId: actorScopeId, |
| 441 | executionId: session.executionId, | 457 | executionId: session.executionId, |
| 442 | interactionId: session.interactionId, | 458 | interactionId: session.interactionId, |
| 443 | }, | 459 | }, |
| @@ -448,8 +464,8 @@ const fromRuntime = (runtime: ExecutorRuntime): Executor => { · 4 unmodified lines | |||
| 448 | provideSourceAuth((service) => | 464 | provideSourceAuth((service) => |
| 449 | service.connectMcpSource({ | 465 | service.connectMcpSource({ |
| 450 | ...payload, | 466 | ...payload, |
| 451 | workspaceId, | 467 | scopeId, |
| 452 | actorAccountId: accountId, | 468 | actorScopeId: actorScopeId, |
| 453 | }), | 469 | }), |
| 454 | ), | 470 | ), |
| 455 | connectBatch: (payload: ExecutorSourceBatchInput) => | 471 | connectBatch: (payload: ExecutorSourceBatchInput) => |
| @@ -457,8 +473,8 @@ const fromRuntime = (runtime: ExecutorRuntime): Executor => { · 1 unmodified line | |||
| 457 | const session = createSdkSourceSession(); | 473 | const session = createSdkSourceSession(); |
| 458 | return service.connectGoogleDiscoveryBatch({ | 474 | return service.connectGoogleDiscoveryBatch({ |
| 459 | ...payload, | 475 | ...payload, |
| 460 | workspaceId, | 476 | scopeId, |
| 461 | actorAccountId: accountId, | 477 | actorScopeId: actorScopeId, |
| 462 | executionId: session.executionId, | 478 | executionId: session.executionId, |
| 463 | interactionId: session.interactionId, | 479 | interactionId: session.interactionId, |
| 464 | }); | 480 | }); |
| @@ -467,22 +483,22 @@ const fromRuntime = (runtime: ExecutorRuntime): Executor => { · 2 unmodified lines | |||
| 467 | url: string; | 483 | url: string; |
| 468 | probeAuth?: Parameters<typeof discoverSource>[0]["probeAuth"]; | 484 | probeAuth?: Parameters<typeof discoverSource>[0]["probeAuth"]; |
| 469 | }) => provide(discoverSource(input)), | 485 | }) => provide(discoverSource(input)), |
| 470 | list: () => provide(listSources({ workspaceId, accountId })), | 486 | list: () => provide(listSources({ scopeId, actorScopeId })), |
| 471 | create: (payload: CreateSourcePayload) => | 487 | create: (payload: CreateSourcePayload) => |
| 472 | provide(createSource({ workspaceId, accountId, payload })), | 488 | provide(createSource({ scopeId, actorScopeId, payload })), |
| 473 | get: (sourceId: Source["id"]) => | 489 | get: (sourceId: Source["id"]) => |
| 474 | provide(getSource({ workspaceId, sourceId, accountId })), | 490 | provide(getSource({ scopeId, sourceId, actorScopeId })), |
| 475 | update: (sourceId: Source["id"], payload: UpdateSourcePayload) => | 491 | update: (sourceId: Source["id"], payload: UpdateSourcePayload) => |
| 476 | provide(updateSource({ workspaceId, sourceId, accountId, payload })), | 492 | provide(updateSource({ scopeId, sourceId, actorScopeId, payload })), |
| 477 | remove: (sourceId: Source["id"]) => | 493 | remove: (sourceId: Source["id"]) => |
| 478 | provide(removeSource({ workspaceId, sourceId })), | 494 | provide(removeSource({ scopeId, sourceId })), |
| 479 | inspection: { | 495 | inspection: { |
| 480 | get: (sourceId: Source["id"]) => | 496 | get: (sourceId: Source["id"]) => |
| 481 | provide(getSourceInspection({ workspaceId, sourceId })), | 497 | provide(getSourceInspection({ scopeId, sourceId })), |
| 482 | tool: ({ sourceId, toolPath }: { sourceId: Source["id"]; toolPath: string }) => | 498 | tool: ({ sourceId, toolPath }: { sourceId: Source["id"]; toolPath: string }) => |
| 483 | provide( | 499 | provide( |
| 484 | getSourceInspectionToolDetail({ | 500 | getSourceInspectionToolDetail({ |
| 485 | workspaceId, | 501 | scopeId, |
| 486 | sourceId, | 502 | sourceId, |
| 487 | toolPath, | 503 | toolPath, |
| 488 | }), | 504 | }), |
| @@ -496,7 +512,7 @@ const fromRuntime = (runtime: ExecutorRuntime): Executor => { · 7 unmodified lines | |||
| 496 | }) => | 512 | }) => |
| 497 | provide( | 513 | provide( |
| 498 | discoverSourceInspectionTools({ | 514 | discoverSourceInspectionTools({ |
| 499 | workspaceId, | 515 | scopeId, |
| 500 | sourceId, | 516 | sourceId, |
| 501 | payload, | 517 | payload, |
| 502 | }), | 518 | }), |
| @@ -505,24 +521,24 @@ const fromRuntime = (runtime: ExecutorRuntime): Executor => { · 2 unmodified lines | |||
| 505 | oauthClients: { | 521 | oauthClients: { |
| 506 | list: (providerKey: string) => | 522 | list: (providerKey: string) => |
| 507 | provideSourceAuth((service) => | 523 | provideSourceAuth((service) => |
| 508 | service.listWorkspaceOauthClients({ | 524 | service.listScopeOauthClients({ |
| 509 | workspaceId, | 525 | scopeId, |
| 510 | providerKey, | 526 | providerKey, |
| 511 | }), | 527 | }), |
| 512 | ), | 528 | ), |
| 513 | create: (payload: CreateWorkspaceOauthClientPayload) => | 529 | create: (payload: CreateScopeOauthClientPayload) => |
| 514 | provideSourceAuth((service) => | 530 | provideSourceAuth((service) => |
| 515 | service.createWorkspaceOauthClient({ | 531 | service.createScopeOauthClient({ |
| 516 | workspaceId, | 532 | scopeId, |
| 517 | providerKey: payload.providerKey, | 533 | providerKey: payload.providerKey, |
| 518 | label: payload.label, | 534 | label: payload.label, |
| 519 | oauthClient: payload.oauthClient, | 535 | oauthClient: payload.oauthClient, |
| 520 | }), | 536 | }), |
| 521 | ), | 537 | ), |
| 522 | remove: (oauthClientId: WorkspaceOauthClient["id"]) => | 538 | remove: (oauthClientId: ScopeOauthClient["id"]) => |
| 523 | provideSourceAuth((service) => | 539 | provideSourceAuth((service) => |
| 524 | service.removeWorkspaceOauthClient({ | 540 | service.removeScopeOauthClient({ |
| 525 | workspaceId, | 541 | scopeId, |
| 526 | oauthClientId, | 542 | oauthClientId, |
| 527 | }), | 543 | }), |
| 528 | ), | 544 | ), |
| @@ -531,7 +547,7 @@ const fromRuntime = (runtime: ExecutorRuntime): Executor => { · 2 unmodified lines | |||
| 531 | remove: (grantId: ProviderAuthGrant["id"]) => | 547 | remove: (grantId: ProviderAuthGrant["id"]) => |
| 532 | provideSourceAuth((service) => | 548 | provideSourceAuth((service) => |
| 533 | service.removeProviderAuthGrant({ | 549 | service.removeProviderAuthGrant({ |
| 534 | workspaceId, | 550 | scopeId, |
| 535 | grantId, | 551 | grantId, |
| 536 | }), | 552 | }), |
| 537 | ), | 553 | ), |
| @@ -542,8 +558,8 @@ const fromRuntime = (runtime: ExecutorRuntime): Executor => { · 4 unmodified lines | |||
| 542 | provideSourceAuth((service) => | 558 | provideSourceAuth((service) => |
| 543 | service.startSourceOAuthSession({ | 559 | service.startSourceOAuthSession({ |
| 544 | ...input, | 560 | ...input, |
| 545 | workspaceId, | 561 | scopeId, |
| 546 | actorAccountId: accountId, | 562 | actorScopeId: actorScopeId, |
| 547 | }), | 563 | }), |
| 548 | ), | 564 | ), |
| 549 | completeSourceAuth: ({ state, code, error, errorDescription }) => | 565 | completeSourceAuth: ({ state, code, error, errorDescription }) => |
| @@ -559,8 +575,8 @@ const fromRuntime = (runtime: ExecutorRuntime): Executor => { · 9 unmodified lines | |||
| 559 | provideSourceAuth((service) => | 575 | provideSourceAuth((service) => |
| 560 | service.completeProviderOauthCallback({ | 576 | service.completeProviderOauthCallback({ |
| 561 | ...input, | 577 | ...input, |
| 562 | workspaceId: input.workspaceId ?? workspaceId, | 578 | scopeId: input.scopeId ?? scopeId, |
| 563 | actorAccountId: input.actorAccountId ?? accountId, | 579 | actorScopeId: input.actorScopeId ?? actorScopeId, |
| 564 | }), | 580 | }), |
| 565 | ), | 581 | ), |
| 566 | }, | 582 | }, |
| @@ -568,20 +584,20 @@ const fromRuntime = (runtime: ExecutorRuntime): Executor => { · 1 unmodified line | |||
| 568 | create: (payload: CreateExecutionPayload) => | 584 | create: (payload: CreateExecutionPayload) => |
| 569 | provide( | 585 | provide( |
| 570 | createExecution({ | 586 | createExecution({ |
| 571 | workspaceId, | 587 | scopeId, |
| 572 | payload, | 588 | payload, |
| 573 | createdByAccountId: accountId, | 589 | createdByScopeId: actorScopeId, |
| 574 | }), | 590 | }), |
| 575 | ), | 591 | ), |
| 576 | get: (executionId: Execution["id"]) => | 592 | get: (executionId: Execution["id"]) => |
| 577 | provide(getExecution({ workspaceId, executionId })), | 593 | provide(getExecution({ scopeId, executionId })), |
| 578 | resume: (executionId: Execution["id"], payload: ResumeExecutionPayload) => | 594 | resume: (executionId: Execution["id"], payload: ResumeExecutionPayload) => |
| 579 | provide( | 595 | provide( |
| 580 | resumeExecution({ | 596 | resumeExecution({ |
| 581 | workspaceId, | 597 | scopeId, |
| 582 | executionId, | 598 | executionId, |
| 583 | payload, | 599 | payload, |
| 584 | resumedByAccountId: accountId, | 600 | resumedByScopeId: actorScopeId, |
| 585 | }), | 601 | }), |
| 586 | ), | 602 | ), |
| 587 | }, | 603 | }, |
| @@ -590,8 +606,9 @@ const fromRuntime = (runtime: ExecutorRuntime): Executor => { · 2 unmodified lines | |||
| 590 | return { | 606 | return { |
| 591 | runtime, | 607 | runtime, |
| 592 | installation, | 608 | installation, |
| 593 | workspaceId, | 609 | scopeId, |
| 594 | accountId, | 610 | actorScopeId, |
| 611 | resolutionScopeIds: installation.resolutionScopeIds, | ||
| 595 | provide, | 612 | provide, |
| 596 | run, | 613 | run, |
| 597 | close: () => runtime.close(), | 614 | close: () => runtime.close(), |
| @@ -1,4 +1,6 @@ | |||
| 1 | import { SecretMaterialPurposeSchema } from "../schema"; | 1 | import { |
| 2 | SecretMaterialPurposeSchema, | ||
| 3 | } from "../schema"; | ||
| 2 | import * as Schema from "effect/Schema"; | 4 | import * as Schema from "effect/Schema"; |
| 3 | 5 | ||
| 4 | export const SecretProviderSchema = Schema.Struct({ | 6 | export const SecretProviderSchema = Schema.Struct({ |
| @@ -2,25 +2,37 @@ import type { · 1 unmodified line | |||
| 2 | Execution, | 2 | Execution, |
| 3 | ExecutionInteraction, | 3 | ExecutionInteraction, |
| 4 | Source, | 4 | Source, |
| 5 | WorkspaceId, | 5 | ScopeId, |
| 6 | } from "../schema"; | 6 | } from "../schema"; |
| 7 | import { | 7 | import { |
| 8 | SourceIdSchema, | 8 | SourceIdSchema, |
| 9 | WorkspaceIdSchema, | 9 | ScopeIdSchema, |
| 10 | } from "../schema"; | 10 | } from "../schema"; |
| 11 | import * as Effect from "effect/Effect"; | 11 | import * as Effect from "effect/Effect"; |
| 12 | import * as Option from "effect/Option"; | 12 | import * as Option from "effect/Option"; |
| 13 | 13 | ||
| 14 | import { submitExecutionInteractionResponse } from "../runtime/execution/service"; | 14 | import { |
| 15 | import { LiveExecutionManagerService } from "../runtime/execution/live"; | 15 | submitExecutionInteractionResponse, |
| 16 | import { operationErrors } from "../runtime/policy/operation-errors"; | 16 | } from "../runtime/execution/service"; |
| 17 | import { InstallationStore } from "../runtime/workspace/storage"; | 17 | import { |
| 18 | import { RuntimeSourceAuthServiceTag } from "../runtime/sources/source-auth-service"; | 18 | LiveExecutionManagerService, |
| 19 | } from "../runtime/execution/live"; | ||
| 20 | import { | ||
| 21 | operationErrors, | ||
| 22 | } from "../runtime/policy/operation-errors"; | ||
| 23 | import { | ||
| 24 | InstallationStore, | ||
| 25 | } from "../runtime/scope/storage"; | ||
| 26 | import { | ||
| 27 | RuntimeSourceAuthServiceTag, | ||
| 28 | } from "../runtime/sources/source-auth-service"; | ||
| 19 | import { | 29 | import { |
| 20 | createSourceCredentialSelectionBearerContent, | 30 | createSourceCredentialSelectionBearerContent, |
| 21 | createSourceCredentialSelectionNoneContent, | 31 | createSourceCredentialSelectionNoneContent, |
| 22 | } from "../runtime/sources/source-credential-interactions"; | 32 | } from "../runtime/sources/source-credential-interactions"; |
| 23 | import { ExecutorStateStore } from "../runtime/executor-state-store"; | 33 | import { |
| 34 | ExecutorStateStore, | ||
| 35 | } from "../runtime/executor-state-store"; | ||
| 24 | 36 | ||
| 25 | const localOps = { | 37 | const localOps = { |
| 26 | installation: operationErrors("local.installation.get"), | 38 | installation: operationErrors("local.installation.get"), |
| @@ -34,7 +46,7 @@ type SourceCredentialInteraction = { · 7 unmodified lines | |||
| 34 | executionId: Execution["id"]; | 46 | executionId: Execution["id"]; |
| 35 | status: ExecutionInteraction["status"]; | 47 | status: ExecutionInteraction["status"]; |
| 36 | message: string; | 48 | message: string; |
| 37 | workspaceId: WorkspaceId; | 49 | scopeId: ScopeId; |
| 38 | sourceId: Source["id"]; | 50 | sourceId: Source["id"]; |
| 39 | sourceLabel: string; | 51 | sourceLabel: string; |
| 40 | endpoint: string; | 52 | endpoint: string; |
| @@ -100,10 +112,10 @@ export const decodeSourceCredentialInteraction = ( · 59 unmodified lines | |||
| 100 | return null; | 112 | return null; |
| 101 | } | 113 | } |
| 102 | 114 | ||
| 103 | const workspaceId = trimOrNull(asString(args.workspaceId)); | 115 | const scopeId = trimOrNull(asString(args.scopeId)); |
| 104 | const sourceId = trimOrNull(asString(args.sourceId)); | 116 | const sourceId = trimOrNull(asString(args.sourceId)); |
| 105 | const message = trimOrNull(asString(elicitation.message)); | 117 | const message = trimOrNull(asString(elicitation.message)); |
| 106 | if (workspaceId === null || sourceId === null || message === null) { | 118 | if (scopeId === null || sourceId === null || message === null) { |
| 107 | return null; | 119 | return null; |
| 108 | } | 120 | } |
| 109 | 121 | ||
| @@ -112,7 +124,7 @@ export const decodeSourceCredentialInteraction = ( · 2 unmodified lines | |||
| 112 | executionId: interaction.executionId, | 124 | executionId: interaction.executionId, |
| 113 | status: interaction.status, | 125 | status: interaction.status, |
| 114 | message, | 126 | message, |
| 115 | workspaceId: WorkspaceIdSchema.make(workspaceId), | 127 | scopeId: ScopeIdSchema.make(scopeId), |
| 116 | sourceId: SourceIdSchema.make(sourceId), | 128 | sourceId: SourceIdSchema.make(sourceId), |
| 117 | }; | 129 | }; |
| 118 | } catch { | 130 | } catch { |
| @@ -121,7 +133,7 @@ export const decodeSourceCredentialInteraction = ( · 2 unmodified lines | |||
| 121 | }; | 133 | }; |
| 122 | 134 | ||
| 123 | const loadSourceCredentialInteraction = (input: { | 135 | const loadSourceCredentialInteraction = (input: { |
| 124 | workspaceId: WorkspaceId; | 136 | scopeId: ScopeId; |
| 125 | sourceId: Source["id"]; | 137 | sourceId: Source["id"]; |
| 126 | interactionId: ExecutionInteraction["id"]; | 138 | interactionId: ExecutionInteraction["id"]; |
| 127 | operation: | 139 | operation: |
| @@ -153,18 +165,18 @@ const loadSourceCredentialInteraction = (input: { · 25 unmodified lines | |||
| 153 | const decoded = decodeSourceCredentialInteraction(stored.value); | 165 | const decoded = decodeSourceCredentialInteraction(stored.value); |
| 154 | if ( | 166 | if ( |
| 155 | decoded === null || | 167 | decoded === null || |
| 156 | decoded.workspaceId !== input.workspaceId || | 168 | decoded.scopeId !== input.scopeId || |
| 157 | decoded.sourceId !== input.sourceId | 169 | decoded.sourceId !== input.sourceId |
| 158 | ) { | 170 | ) { |
| 159 | return yield* input.operation.notFound( | 171 | return yield* input.operation.notFound( |
| 160 | "Source credential request not found", | 172 | "Source credential request not found", |
| 161 | `workspaceId=${input.workspaceId} sourceId=${input.sourceId} interactionId=${input.interactionId}`, | 173 | `scopeId=${input.scopeId} sourceId=${input.sourceId} interactionId=${input.interactionId}`, |
| 162 | ); | 174 | ); |
| 163 | } | 175 | } |
| 164 | 176 | ||
| 165 | const source = yield* sourceAuthService | 177 | const source = yield* sourceAuthService |
| 166 | .getSourceById({ | 178 | .getSourceById({ |
| 167 | workspaceId: input.workspaceId, | 179 | scopeId: input.scopeId, |
| 168 | sourceId: input.sourceId, | 180 | sourceId: input.sourceId, |
| 169 | }) | 181 | }) |
| 170 | .pipe( | 182 | .pipe( |
| @@ -197,7 +209,7 @@ export const getLocalInstallation = () => · 26 unmodified lines | |||
| 197 | }); | 209 | }); |
| 198 | 210 | ||
| 199 | export const getSourceCredentialInteraction = (input: { | 211 | export const getSourceCredentialInteraction = (input: { |
| 200 | workspaceId: WorkspaceId; | 212 | scopeId: ScopeId; |
| 201 | sourceId: Source["id"]; | 213 | sourceId: Source["id"]; |
| 202 | interactionId: ExecutionInteraction["id"]; | 214 | interactionId: ExecutionInteraction["id"]; |
| 203 | }) => | 215 | }) => |
| @@ -207,7 +219,7 @@ export const getSourceCredentialInteraction = (input: { · 3 unmodified lines | |||
| 207 | }); | 219 | }); |
| 208 | 220 | ||
| 209 | export const submitSourceCredentialInteraction = (input: { | 221 | export const submitSourceCredentialInteraction = (input: { |
| 210 | workspaceId: WorkspaceId; | 222 | scopeId: ScopeId; |
| 211 | sourceId: Source["id"]; | 223 | sourceId: Source["id"]; |
| 212 | interactionId: ExecutionInteraction["id"]; | 224 | interactionId: ExecutionInteraction["id"]; |
| 213 | action: "submit" | "continue" | "cancel"; | 225 | action: "submit" | "continue" | "cancel"; |
| @@ -215,7 +227,7 @@ export const submitSourceCredentialInteraction = (input: { · 1 unmodified line | |||
| 215 | }) => | 227 | }) => |
| 216 | Effect.gen(function* () { | 228 | Effect.gen(function* () { |
| 217 | const interaction = yield* loadSourceCredentialInteraction({ | 229 | const interaction = yield* loadSourceCredentialInteraction({ |
| 218 | workspaceId: input.workspaceId, | 230 | scopeId: input.scopeId, |
| 219 | sourceId: input.sourceId, | 231 | sourceId: input.sourceId, |
| 220 | interactionId: input.interactionId, | 232 | interactionId: input.interactionId, |
| 221 | operation: localOps.sourceCredentialSubmit, | 233 | operation: localOps.sourceCredentialSubmit, |
| @@ -370,7 +382,7 @@ export const submitSourceCredentialInteraction = (input: { · 148 unmodified lines | |||
| 370 | }); | 382 | }); |
| 371 | 383 | ||
| 372 | export const completeSourceCredentialSetup = (input: { | 384 | export const completeSourceCredentialSetup = (input: { |
| 373 | workspaceId: WorkspaceId; | 385 | scopeId: ScopeId; |
| 374 | sourceId: Source["id"]; | 386 | sourceId: Source["id"]; |
| 375 | state: string; | 387 | state: string; |
| 376 | code?: string | null; | 388 | code?: string | null; |
| @@ -1,7 +1,9 @@ | |||
| 1 | import * as Effect from "effect/Effect"; | 1 | import * as Effect from "effect/Effect"; |
| 2 | import * as Option from "effect/Option"; | 2 | import * as Option from "effect/Option"; |
| 3 | 3 | ||
| 4 | import { SecretMaterialIdSchema } from "../schema"; | 4 | import { |
| 5 | SecretMaterialIdSchema, | ||
| 6 | } from "../schema"; | ||
| 5 | import { | 7 | import { |
| 6 | type CreateSecretPayload, | 8 | type CreateSecretPayload, |
| 7 | type CreateSecretResult, | 9 | type CreateSecretResult, |
| @@ -16,15 +18,21 @@ import { · 8 unmodified lines | |||
| 16 | ControlPlaneNotFoundError, | 18 | ControlPlaneNotFoundError, |
| 17 | ControlPlaneStorageError, | 19 | ControlPlaneStorageError, |
| 18 | } from "../errors"; | 20 | } from "../errors"; |
| 19 | import { requireRuntimeLocalWorkspace } from "../runtime/workspace/runtime-context"; | 21 | import { |
| 22 | requireRuntimeLocalScope, | ||
| 23 | } from "../runtime/scope/runtime-context"; | ||
| 20 | import { | 24 | import { |
| 21 | LocalInstanceConfigService, | 25 | LocalInstanceConfigService, |
| 22 | SecretMaterialDeleterService, | 26 | SecretMaterialDeleterService, |
| 23 | SecretMaterialStorerService, | 27 | SecretMaterialStorerService, |
| 24 | SecretMaterialUpdaterService, | 28 | SecretMaterialUpdaterService, |
| 25 | } from "../runtime/workspace/secret-material-providers"; | 29 | } from "../runtime/scope/secret-material-providers"; |
| 26 | import { RuntimeSourceStoreService } from "../runtime/sources/source-store"; | 30 | import { |
| 27 | import { ExecutorStateStore } from "../runtime/executor-state-store"; | 31 | RuntimeSourceStoreService, |
| 32 | } from "../runtime/sources/source-store"; | ||
| 33 | import { | ||
| 34 | ExecutorStateStore, | ||
| 35 | } from "../runtime/executor-state-store"; | ||
| 28 | 36 | ||
| 29 | const secretStorageError = (operation: string, message: string) => | 37 | const secretStorageError = (operation: string, message: string) => |
| 30 | new ControlPlaneStorageError({ | 38 | new ControlPlaneStorageError({ |
| @@ -40,9 +48,9 @@ export const listLocalSecrets = () => · 9 unmodified lines | |||
| 40 | Effect.gen(function* () { | 48 | Effect.gen(function* () { |
| 41 | const store = yield* ExecutorStateStore; | 49 | const store = yield* ExecutorStateStore; |
| 42 | const sourceStore = yield* RuntimeSourceStoreService; | 50 | const sourceStore = yield* RuntimeSourceStoreService; |
| 43 | const runtimeLocalWorkspace = yield* requireRuntimeLocalWorkspace().pipe( | 51 | const runtimeLocalScope = yield* requireRuntimeLocalScope().pipe( |
| 44 | Effect.mapError(() => | 52 | Effect.mapError(() => |
| 45 | secretStorageError("secrets.list", "Failed resolving local workspace."), | 53 | secretStorageError("secrets.list", "Failed resolving local scope."), |
| 46 | ), | 54 | ), |
| 47 | ); | 55 | ); |
| 48 | const secretMaterials = yield* store.secretMaterials | 56 | const secretMaterials = yield* store.secretMaterials |
| @@ -53,10 +61,10 @@ export const listLocalSecrets = () => · 4 unmodified lines | |||
| 53 | ), | 61 | ), |
| 54 | ); | 62 | ); |
| 55 | const linkedSourcesMap = yield* sourceStore | 63 | const linkedSourcesMap = yield* sourceStore |
| 56 | .listLinkedSecretSourcesInWorkspace( | 64 | .listLinkedSecretSourcesInScope( |
| 57 | runtimeLocalWorkspace.installation.workspaceId, | 65 | runtimeLocalScope.installation.scopeId, |
| 58 | { | 66 | { |
| 59 | actorAccountId: runtimeLocalWorkspace.installation.accountId, | 67 | actorScopeId: runtimeLocalScope.installation.actorScopeId, |
| 60 | }, | 68 | }, |
| 61 | ) | 69 | ) |
| 62 | .pipe( | 70 | .pipe( |
| @@ -1,23 +1,25 @@ | |||
| 1 | import { | 1 | import { |
| 2 | LocalWorkspacePolicyApprovalModeSchema, | 2 | LocalScopePolicyApprovalModeSchema, |
| 3 | LocalWorkspacePolicyEffectSchema, | 3 | LocalScopePolicyEffectSchema, |
| 4 | } from "../schema"; | 4 | } from "../schema"; |
| 5 | import * as Schema from "effect/Schema"; | 5 | import * as Schema from "effect/Schema"; |
| 6 | 6 | ||
| 7 | import { OptionalTrimmedNonEmptyStringSchema } from "../string-schemas"; | 7 | import { |
| 8 | OptionalTrimmedNonEmptyStringSchema, | ||
| 9 | } from "../string-schemas"; | ||
| 8 | 10 | ||
| 9 | const LocalWorkspacePolicyPayloadSchema = Schema.Struct({ | 11 | const LocalScopePolicyPayloadSchema = Schema.Struct({ |
| 10 | resourcePattern: OptionalTrimmedNonEmptyStringSchema, | 12 | resourcePattern: OptionalTrimmedNonEmptyStringSchema, |
| 11 | effect: Schema.optional(LocalWorkspacePolicyEffectSchema), | 13 | effect: Schema.optional(LocalScopePolicyEffectSchema), |
| 12 | approvalMode: Schema.optional(LocalWorkspacePolicyApprovalModeSchema), | 14 | approvalMode: Schema.optional(LocalScopePolicyApprovalModeSchema), |
| 13 | priority: Schema.optional(Schema.Number), | 15 | priority: Schema.optional(Schema.Number), |
| 14 | enabled: Schema.optional(Schema.Boolean), | 16 | enabled: Schema.optional(Schema.Boolean), |
| 15 | }); | 17 | }); |
| 16 | 18 | ||
| 17 | export const CreatePolicyPayloadSchema = LocalWorkspacePolicyPayloadSchema; | 19 | export const CreatePolicyPayloadSchema = LocalScopePolicyPayloadSchema; |
| 18 | 20 | ||
| 19 | export type CreatePolicyPayload = typeof CreatePolicyPayloadSchema.Type; | 21 | export type CreatePolicyPayload = typeof CreatePolicyPayloadSchema.Type; |
| 20 | 22 | ||
| 21 | export const UpdatePolicyPayloadSchema = LocalWorkspacePolicyPayloadSchema; | 23 | export const UpdatePolicyPayloadSchema = LocalScopePolicyPayloadSchema; |
| 22 | 24 | ||
| 23 | export type UpdatePolicyPayload = typeof UpdatePolicyPayloadSchema.Type; | 25 | export type UpdatePolicyPayload = typeof UpdatePolicyPayloadSchema.Type; |
| @@ -1,4 +1,6 @@ | |||
| 1 | import { createHash } from "node:crypto"; | 1 | import { |
| 2 | createHash, | ||
| 3 | } from "node:crypto"; | ||
| 2 | 4 | ||
| 3 | import type { | 5 | import type { |
| 4 | CreatePolicyPayload, | 6 | CreatePolicyPayload, |
| @@ -7,23 +9,29 @@ import type { · 2 unmodified lines | |||
| 7 | import { | 9 | import { |
| 8 | PolicyIdSchema, | 10 | PolicyIdSchema, |
| 9 | type LocalExecutorConfig, | 11 | type LocalExecutorConfig, |
| 10 | type LocalWorkspacePolicy, | 12 | type LocalScopePolicy, |
| 11 | type PolicyId, | 13 | type PolicyId, |
| 12 | type WorkspaceId, | 14 | type ScopeId, |
| 13 | } from "../schema"; | 15 | } from "../schema"; |
| 14 | import * as Effect from "effect/Effect"; | 16 | import * as Effect from "effect/Effect"; |
| 15 | 17 | ||
| 16 | import { requireRuntimeLocalWorkspace } from "../runtime/workspace/runtime-context"; | 18 | import { |
| 19 | requireRuntimeLocalScope, | ||
| 20 | } from "../runtime/scope/runtime-context"; | ||
| 17 | import type { | 21 | import type { |
| 18 | WorkspaceConfigStoreShape, | 22 | ScopeConfigStoreShape, |
| 19 | WorkspaceStateStoreShape, | 23 | ScopeStateStoreShape, |
| 20 | } from "../runtime/workspace/storage"; | 24 | } from "../runtime/scope/storage"; |
| 25 | import { | ||
| 26 | ScopeConfigStore, | ||
| 27 | ScopeStateStore, | ||
| 28 | } from "../runtime/scope/storage"; | ||
| 29 | import { | ||
| 30 | type LocalScopeState, | ||
| 31 | } from "../runtime/scope-state"; | ||
| 21 | import { | 32 | import { |
| 22 | WorkspaceConfigStore, | 33 | derivePolicyConfigKey, |
| 23 | WorkspaceStateStore, | 34 | } from "../runtime/scope/scope-sync"; |
| 24 | } from "../runtime/workspace/storage"; | ||
| 25 | import { type LocalWorkspaceState } from "../runtime/workspace-state"; | ||
| 26 | import { derivePolicyConfigKey } from "../runtime/workspace/workspace-sync"; | ||
| 27 | import { | 35 | import { |
| 28 | type OperationErrors, | 36 | type OperationErrors, |
| 29 | operationErrors, | 37 | operationErrors, |
| @@ -39,34 +47,34 @@ const policyOps = { · 9 unmodified lines | |||
| 39 | 47 | ||
| 40 | const cloneJson = <T>(value: T): T => JSON.parse(JSON.stringify(value)) as T; | 48 | const cloneJson = <T>(value: T): T => JSON.parse(JSON.stringify(value)) as T; |
| 41 | 49 | ||
| 42 | const workspacePolicyStableKey = (input: { | 50 | const scopePolicyStableKey = (input: { |
| 43 | workspaceId: WorkspaceId; | 51 | scopeId: ScopeId; |
| 44 | workspaceRoot?: string | null; | 52 | scopeRoot?: string | null; |
| 45 | }): string => input.workspaceRoot?.trim() || input.workspaceId; | 53 | }): string => input.scopeRoot?.trim() || input.scopeId; |
| 46 | 54 | ||
| 47 | const localPolicyIdForKey = (input: { | 55 | const localPolicyIdForKey = (input: { |
| 48 | workspaceStableKey: string; | 56 | scopeStableKey: string; |
| 49 | key: string; | 57 | key: string; |
| 50 | }): PolicyId => | 58 | }): PolicyId => |
| 51 | PolicyIdSchema.make( | 59 | PolicyIdSchema.make( |
| 52 | `pol_local_${createHash("sha256").update(`${input.workspaceStableKey}:${input.key}`).digest("hex").slice(0, 16)}`, | 60 | `pol_local_${createHash("sha256").update(`${input.scopeStableKey}:${input.key}`).digest("hex").slice(0, 16)}`, |
| 53 | ); | 61 | ); |
| 54 | 62 | ||
| 55 | const toLocalWorkspacePolicy = (input: { | 63 | const toLocalScopePolicy = (input: { |
| 56 | workspaceId: WorkspaceId; | 64 | scopeId: ScopeId; |
| 57 | workspaceStableKey: string; | 65 | scopeStableKey: string; |
| 58 | key: string; | 66 | key: string; |
| 59 | policyConfig: NonNullable<LocalExecutorConfig["policies"]>[string]; | 67 | policyConfig: NonNullable<LocalExecutorConfig["policies"]>[string]; |
| 60 | state: LocalWorkspaceState["policies"][string] | undefined; | 68 | state: LocalScopeState["policies"][string] | undefined; |
| 61 | }): LocalWorkspacePolicy => ({ | 69 | }): LocalScopePolicy => ({ |
| 62 | id: | 70 | id: |
| 63 | input.state?.id ?? | 71 | input.state?.id ?? |
| 64 | localPolicyIdForKey({ | 72 | localPolicyIdForKey({ |
| 65 | workspaceStableKey: input.workspaceStableKey, | 73 | scopeStableKey: input.scopeStableKey, |
| 66 | key: input.key, | 74 | key: input.key, |
| 67 | }), | 75 | }), |
| 68 | key: input.key, | 76 | key: input.key, |
| 69 | workspaceId: input.workspaceId, | 77 | scopeId: input.scopeId, |
| 70 | resourcePattern: input.policyConfig.match.trim(), | 78 | resourcePattern: input.policyConfig.match.trim(), |
| 71 | effect: input.policyConfig.action, | 79 | effect: input.policyConfig.action, |
| 72 | approvalMode: input.policyConfig.approval === "manual" ? "required" : "auto", | 80 | approvalMode: input.policyConfig.approval === "manual" ? "required" : "auto", |
| @@ -76,51 +84,51 @@ const toLocalWorkspacePolicy = (input: { · 3 unmodified lines | |||
| 76 | updatedAt: input.state?.updatedAt ?? Date.now(), | 84 | updatedAt: input.state?.updatedAt ?? Date.now(), |
| 77 | }); | 85 | }); |
| 78 | 86 | ||
| 79 | export const loadRuntimeLocalWorkspacePolicies = (workspaceId: WorkspaceId) => | 87 | export const loadRuntimeLocalScopePolicies = (scopeId: ScopeId) => |
| 80 | Effect.gen(function* () { | 88 | Effect.gen(function* () { |
| 81 | const runtimeLocalWorkspace = | 89 | const runtimeLocalScope = |
| 82 | yield* requireRuntimeLocalWorkspace(workspaceId); | 90 | yield* requireRuntimeLocalScope(scopeId); |
| 83 | const workspaceConfigStore = yield* WorkspaceConfigStore; | 91 | const scopeConfigStore = yield* ScopeConfigStore; |
| 84 | const workspaceStateStore = yield* WorkspaceStateStore; | 92 | const scopeStateStore = yield* ScopeStateStore; |
| 85 | const loadedConfig = yield* workspaceConfigStore.load(); | 93 | const loadedConfig = yield* scopeConfigStore.load(); |
| 86 | const workspaceState = yield* workspaceStateStore.load(); | 94 | const scopeState = yield* scopeStateStore.load(); |
| 87 | 95 | ||
| 88 | const policies = Object.entries(loadedConfig.config?.policies ?? {}).map( | 96 | const policies = Object.entries(loadedConfig.config?.policies ?? {}).map( |
| 89 | ([key, policyConfig]) => | 97 | ([key, policyConfig]) => |
| 90 | toLocalWorkspacePolicy({ | 98 | toLocalScopePolicy({ |
| 91 | workspaceId, | 99 | scopeId, |
| 92 | workspaceStableKey: workspacePolicyStableKey({ | 100 | scopeStableKey: scopePolicyStableKey({ |
| 93 | workspaceId, | 101 | scopeId, |
| 94 | workspaceRoot: runtimeLocalWorkspace.workspace.workspaceRoot, | 102 | scopeRoot: runtimeLocalScope.scope.scopeRoot, |
| 95 | }), | 103 | }), |
| 96 | key, | 104 | key, |
| 97 | policyConfig, | 105 | policyConfig, |
| 98 | state: workspaceState.policies[key], | 106 | state: scopeState.policies[key], |
| 99 | }), | 107 | }), |
| 100 | ); | 108 | ); |
| 101 | 109 | ||
| 102 | return { | 110 | return { |
| 103 | runtimeLocalWorkspace, | 111 | runtimeLocalScope, |
| 104 | loadedConfig, | 112 | loadedConfig, |
| 105 | workspaceState, | 113 | scopeState, |
| 106 | policies, | 114 | policies, |
| 107 | }; | 115 | }; |
| 108 | }); | 116 | }); |
| 109 | 117 | ||
| 110 | const writeLocalPolicyFiles = (input: { | 118 | const writeLocalPolicyFiles = (input: { |
| 111 | operation: OperationErrors; | 119 | operation: OperationErrors; |
| 112 | workspaceConfigStore: WorkspaceConfigStoreShape; | 120 | scopeConfigStore: ScopeConfigStoreShape; |
| 113 | workspaceStateStore: WorkspaceStateStoreShape; | 121 | scopeStateStore: ScopeStateStoreShape; |
| 114 | projectConfig: LocalExecutorConfig; | 122 | projectConfig: LocalExecutorConfig; |
| 115 | workspaceState: LocalWorkspaceState; | 123 | scopeState: LocalScopeState; |
| 116 | }) => | 124 | }) => |
| 117 | Effect.all( | 125 | Effect.all( |
| 118 | [ | 126 | [ |
| 119 | input.workspaceConfigStore.writeProject({ | 127 | input.scopeConfigStore.writeProject({ |
| 120 | config: input.projectConfig, | 128 | config: input.projectConfig, |
| 121 | }), | 129 | }), |
| 122 | input.workspaceStateStore.write({ | 130 | input.scopeStateStore.write({ |
| 123 | state: input.workspaceState, | 131 | state: input.scopeState, |
| 124 | }), | 132 | }), |
| 125 | ], | 133 | ], |
| 126 | { discard: true }, | 134 | { discard: true }, |
| @@ -128,16 +136,16 @@ const writeLocalPolicyFiles = (input: { · 1 unmodified line | |||
| 128 | Effect.mapError((cause) => | 136 | Effect.mapError((cause) => |
| 129 | input.operation.unknownStorage( | 137 | input.operation.unknownStorage( |
| 130 | cause, | 138 | cause, |
| 131 | "Failed writing local workspace policy files", | 139 | "Failed writing local scope policy files", |
| 132 | ), | 140 | ), |
| 133 | ), | 141 | ), |
| 134 | ); | 142 | ); |
| 135 | 143 | ||
| 136 | const loadWorkspacePolicyContext = ( | 144 | const loadScopePolicyContext = ( |
| 137 | operation: OperationErrors, | 145 | operation: OperationErrors, |
| 138 | workspaceId: WorkspaceId, | 146 | scopeId: ScopeId, |
| 139 | ) => | 147 | ) => |
| 140 | requireRuntimeLocalWorkspace(workspaceId).pipe( | 148 | requireRuntimeLocalScope(scopeId).pipe( |
| 141 | Effect.mapError((cause) => | 149 | Effect.mapError((cause) => |
| 142 | operation.notFound( | 150 | operation.notFound( |
| 143 | "Workspace not found", | 151 | "Workspace not found", |
| @@ -146,46 +154,46 @@ const loadWorkspacePolicyContext = ( · 2 unmodified lines | |||
| 146 | ), | 154 | ), |
| 147 | ); | 155 | ); |
| 148 | 156 | ||
| 149 | export const listPolicies = (workspaceId: WorkspaceId) => | 157 | export const listPolicies = (scopeId: ScopeId) => |
| 150 | Effect.gen(function* () { | 158 | Effect.gen(function* () { |
| 151 | yield* loadWorkspacePolicyContext(policyOps.list, workspaceId); | 159 | yield* loadScopePolicyContext(policyOps.list, scopeId); |
| 152 | const localWorkspace = yield* loadRuntimeLocalWorkspacePolicies( | 160 | const localScope = yield* loadRuntimeLocalScopePolicies( |
| 153 | workspaceId, | 161 | scopeId, |
| 154 | ).pipe( | 162 | ).pipe( |
| 155 | Effect.mapError((cause) => | 163 | Effect.mapError((cause) => |
| 156 | policyOps.list.unknownStorage( | 164 | policyOps.list.unknownStorage( |
| 157 | cause, | 165 | cause, |
| 158 | "Failed loading local workspace policies", | 166 | "Failed loading local scope policies", |
| 159 | ), | 167 | ), |
| 160 | ), | 168 | ), |
| 161 | ); | 169 | ); |
| 162 | return localWorkspace.policies; | 170 | return localScope.policies; |
| 163 | }); | 171 | }); |
| 164 | 172 | ||
| 165 | export const createPolicy = (input: { | 173 | export const createPolicy = (input: { |
| 166 | workspaceId: WorkspaceId; | 174 | scopeId: ScopeId; |
| 167 | payload: CreatePolicyPayload; | 175 | payload: CreatePolicyPayload; |
| 168 | }) => | 176 | }) => |
| 169 | Effect.gen(function* () { | 177 | Effect.gen(function* () { |
| 170 | const runtimeLocalWorkspace = yield* loadWorkspacePolicyContext( | 178 | const runtimeLocalScope = yield* loadScopePolicyContext( |
| 171 | policyOps.create, | 179 | policyOps.create, |
| 172 | input.workspaceId, | 180 | input.scopeId, |
| 173 | ); | 181 | ); |
| 174 | const workspaceConfigStore = yield* WorkspaceConfigStore; | 182 | const scopeConfigStore = yield* ScopeConfigStore; |
| 175 | const workspaceStateStore = yield* WorkspaceStateStore; | 183 | const scopeStateStore = yield* ScopeStateStore; |
| 176 | const localWorkspace = yield* loadRuntimeLocalWorkspacePolicies( | 184 | const localScope = yield* loadRuntimeLocalScopePolicies( |
| 177 | input.workspaceId, | 185 | input.scopeId, |
| 178 | ).pipe( | 186 | ).pipe( |
| 179 | Effect.mapError((cause) => | 187 | Effect.mapError((cause) => |
| 180 | policyOps.create.unknownStorage( | 188 | policyOps.create.unknownStorage( |
| 181 | cause, | 189 | cause, |
| 182 | "Failed loading local workspace policies", | 190 | "Failed loading local scope policies", |
| 183 | ), | 191 | ), |
| 184 | ), | 192 | ), |
| 185 | ); | 193 | ); |
| 186 | const now = Date.now(); | 194 | const now = Date.now(); |
| 187 | const projectConfig = cloneJson( | 195 | const projectConfig = cloneJson( |
| 188 | localWorkspace.loadedConfig.projectConfig ?? {}, | 196 | localScope.loadedConfig.projectConfig ?? {}, |
| 189 | ); | 197 | ); |
| 190 | const policies = { ...projectConfig.policies }; | 198 | const policies = { ...projectConfig.policies }; |
| 191 | const key = derivePolicyConfigKey( | 199 | const key = derivePolicyConfigKey( |
| @@ -210,18 +218,18 @@ export const createPolicy = (input: { · 18 unmodified lines | |||
| 210 | : {}), | 218 | : {}), |
| 211 | }; | 219 | }; |
| 212 | 220 | ||
| 213 | const existingState = localWorkspace.workspaceState.policies[key]; | 221 | const existingState = localScope.scopeState.policies[key]; |
| 214 | const workspaceState: LocalWorkspaceState = { | 222 | const scopeState: LocalScopeState = { |
| 215 | ...localWorkspace.workspaceState, | 223 | ...localScope.scopeState, |
| 216 | policies: { | 224 | policies: { |
| 217 | ...localWorkspace.workspaceState.policies, | 225 | ...localScope.scopeState.policies, |
| 218 | [key]: { | 226 | [key]: { |
| 219 | id: | 227 | id: |
| 220 | existingState?.id ?? | 228 | existingState?.id ?? |
| 221 | localPolicyIdForKey({ | 229 | localPolicyIdForKey({ |
| 222 | workspaceStableKey: workspacePolicyStableKey({ | 230 | scopeStableKey: scopePolicyStableKey({ |
| 223 | workspaceId: input.workspaceId, | 231 | scopeId: input.scopeId, |
| 224 | workspaceRoot: runtimeLocalWorkspace.workspace.workspaceRoot, | 232 | scopeRoot: runtimeLocalScope.scope.scopeRoot, |
| 225 | }), | 233 | }), |
| 226 | key, | 234 | key, |
| 227 | }), | 235 | }), |
| @@ -233,91 +241,91 @@ export const createPolicy = (input: { · 5 unmodified lines | |||
| 233 | 241 | ||
| 234 | yield* writeLocalPolicyFiles({ | 242 | yield* writeLocalPolicyFiles({ |
| 235 | operation: policyOps.create, | 243 | operation: policyOps.create, |
| 236 | workspaceConfigStore, | 244 | scopeConfigStore, |
| 237 | workspaceStateStore, | 245 | scopeStateStore, |
| 238 | projectConfig: { | 246 | projectConfig: { |
| 239 | ...projectConfig, | 247 | ...projectConfig, |
| 240 | policies, | 248 | policies, |
| 241 | }, | 249 | }, |
| 242 | workspaceState, | 250 | scopeState, |
| 243 | }); | 251 | }); |
| 244 | 252 | ||
| 245 | return toLocalWorkspacePolicy({ | 253 | return toLocalScopePolicy({ |
| 246 | workspaceId: input.workspaceId, | 254 | scopeId: input.scopeId, |
| 247 | workspaceStableKey: workspacePolicyStableKey({ | 255 | scopeStableKey: scopePolicyStableKey({ |
| 248 | workspaceId: input.workspaceId, | 256 | scopeId: input.scopeId, |
| 249 | workspaceRoot: runtimeLocalWorkspace.workspace.workspaceRoot, | 257 | scopeRoot: runtimeLocalScope.scope.scopeRoot, |
| 250 | }), | 258 | }), |
| 251 | key, | 259 | key, |
| 252 | policyConfig: policies[key]!, | 260 | policyConfig: policies[key]!, |
| 253 | state: workspaceState.policies[key], | 261 | state: scopeState.policies[key], |
| 254 | }); | 262 | }); |
| 255 | }); | 263 | }); |
| 256 | 264 | ||
| 257 | export const getPolicy = (input: { | 265 | export const getPolicy = (input: { |
| 258 | workspaceId: WorkspaceId; | 266 | scopeId: ScopeId; |
| 259 | policyId: PolicyId; | 267 | policyId: PolicyId; |
| 260 | }) => | 268 | }) => |
| 261 | Effect.gen(function* () { | 269 | Effect.gen(function* () { |
| 262 | yield* loadWorkspacePolicyContext(policyOps.get, input.workspaceId); | 270 | yield* loadScopePolicyContext(policyOps.get, input.scopeId); |
| 263 | const localWorkspace = yield* loadRuntimeLocalWorkspacePolicies( | 271 | const localScope = yield* loadRuntimeLocalScopePolicies( |
| 264 | input.workspaceId, | 272 | input.scopeId, |
| 265 | ).pipe( | 273 | ).pipe( |
| 266 | Effect.mapError((cause) => | 274 | Effect.mapError((cause) => |
| 267 | policyOps.get.unknownStorage( | 275 | policyOps.get.unknownStorage( |
| 268 | cause, | 276 | cause, |
| 269 | "Failed loading local workspace policies", | 277 | "Failed loading local scope policies", |
| 270 | ), | 278 | ), |
| 271 | ), | 279 | ), |
| 272 | ); | 280 | ); |
| 273 | const policy = | 281 | const policy = |
| 274 | localWorkspace.policies.find( | 282 | localScope.policies.find( |
| 275 | (candidate) => candidate.id === input.policyId, | 283 | (candidate) => candidate.id === input.policyId, |
| 276 | ) ?? null; | 284 | ) ?? null; |
| 277 | if (policy === null) { | 285 | if (policy === null) { |
| 278 | return yield* policyOps.get.notFound( | 286 | return yield* policyOps.get.notFound( |
| 279 | "Policy not found", | 287 | "Policy not found", |
| 280 | `workspaceId=${input.workspaceId} policyId=${input.policyId}`, | 288 | `scopeId=${input.scopeId} policyId=${input.policyId}`, |
| 281 | ); | 289 | ); |
| 282 | } | 290 | } |
| 283 | return policy; | 291 | return policy; |
| 284 | }); | 292 | }); |
| 285 | 293 | ||
| 286 | export const updatePolicy = (input: { | 294 | export const updatePolicy = (input: { |
| 287 | workspaceId: WorkspaceId; | 295 | scopeId: ScopeId; |
| 288 | policyId: PolicyId; | 296 | policyId: PolicyId; |
| 289 | payload: UpdatePolicyPayload; | 297 | payload: UpdatePolicyPayload; |
| 290 | }) => | 298 | }) => |
| 291 | Effect.gen(function* () { | 299 | Effect.gen(function* () { |
| 292 | const runtimeLocalWorkspace = yield* loadWorkspacePolicyContext( | 300 | const runtimeLocalScope = yield* loadScopePolicyContext( |
| 293 | policyOps.update, | 301 | policyOps.update, |
| 294 | input.workspaceId, | 302 | input.scopeId, |
| 295 | ); | 303 | ); |
| 296 | const workspaceConfigStore = yield* WorkspaceConfigStore; | 304 | const scopeConfigStore = yield* ScopeConfigStore; |
| 297 | const workspaceStateStore = yield* WorkspaceStateStore; | 305 | const scopeStateStore = yield* ScopeStateStore; |
| 298 | const localWorkspace = yield* loadRuntimeLocalWorkspacePolicies( | 306 | const localScope = yield* loadRuntimeLocalScopePolicies( |
| 299 | input.workspaceId, | 307 | input.scopeId, |
| 300 | ).pipe( | 308 | ).pipe( |
| 301 | Effect.mapError((cause) => | 309 | Effect.mapError((cause) => |
| 302 | policyOps.update.unknownStorage( | 310 | policyOps.update.unknownStorage( |
| 303 | cause, | 311 | cause, |
| 304 | "Failed loading local workspace policies", | 312 | "Failed loading local scope policies", |
| 305 | ), | 313 | ), |
| 306 | ), | 314 | ), |
| 307 | ); | 315 | ); |
| 308 | const existing = | 316 | const existing = |
| 309 | localWorkspace.policies.find( | 317 | localScope.policies.find( |
| 310 | (candidate) => candidate.id === input.policyId, | 318 | (candidate) => candidate.id === input.policyId, |
| 311 | ) ?? null; | 319 | ) ?? null; |
| 312 | if (existing === null) { | 320 | if (existing === null) { |
| 313 | return yield* policyOps.update.notFound( | 321 | return yield* policyOps.update.notFound( |
| 314 | "Policy not found", | 322 | "Policy not found", |
| 315 | `workspaceId=${input.workspaceId} policyId=${input.policyId}`, | 323 | `scopeId=${input.scopeId} policyId=${input.policyId}`, |
| 316 | ); | 324 | ); |
| 317 | } | 325 | } |
| 318 | 326 | ||
| 319 | const projectConfig = cloneJson( | 327 | const projectConfig = cloneJson( |
| 320 | localWorkspace.loadedConfig.projectConfig ?? {}, | 328 | localScope.loadedConfig.projectConfig ?? {}, |
| 321 | ); | 329 | ); |
| 322 | const policies = { ...projectConfig.policies }; | 330 | const policies = { ...projectConfig.policies }; |
| 323 | const existingConfig = policies[existing.key]!; | 331 | const existingConfig = policies[existing.key]!; |
| @@ -345,11 +353,11 @@ export const updatePolicy = (input: { · 21 unmodified lines | |||
| 345 | }; | 353 | }; |
| 346 | 354 | ||
| 347 | const updatedAt = Date.now(); | 355 | const updatedAt = Date.now(); |
| 348 | const existingState = localWorkspace.workspaceState.policies[existing.key]; | 356 | const existingState = localScope.scopeState.policies[existing.key]; |
| 349 | const workspaceState: LocalWorkspaceState = { | 357 | const scopeState: LocalScopeState = { |
| 350 | ...localWorkspace.workspaceState, | 358 | ...localScope.scopeState, |
| 351 | policies: { | 359 | policies: { |
| 352 | ...localWorkspace.workspaceState.policies, | 360 | ...localScope.scopeState.policies, |
| 353 | [existing.key]: { | 361 | [existing.key]: { |
| 354 | id: existing.id, | 362 | id: existing.id, |
| 355 | createdAt: existingState?.createdAt ?? existing.createdAt, | 363 | createdAt: existingState?.createdAt ?? existing.createdAt, |
| @@ -360,50 +368,50 @@ export const updatePolicy = (input: { · 4 unmodified lines | |||
| 360 | 368 | ||
| 361 | yield* writeLocalPolicyFiles({ | 369 | yield* writeLocalPolicyFiles({ |
| 362 | operation: policyOps.update, | 370 | operation: policyOps.update, |
| 363 | workspaceConfigStore, | 371 | scopeConfigStore, |
| 364 | workspaceStateStore, | 372 | scopeStateStore, |
| 365 | projectConfig: { | 373 | projectConfig: { |
| 366 | ...projectConfig, | 374 | ...projectConfig, |
| 367 | policies, | 375 | policies, |
| 368 | }, | 376 | }, |
| 369 | workspaceState, | 377 | scopeState, |
| 370 | }); | 378 | }); |
| 371 | 379 | ||
| 372 | return toLocalWorkspacePolicy({ | 380 | return toLocalScopePolicy({ |
| 373 | workspaceId: input.workspaceId, | 381 | scopeId: input.scopeId, |
| 374 | workspaceStableKey: workspacePolicyStableKey({ | 382 | scopeStableKey: scopePolicyStableKey({ |
| 375 | workspaceId: input.workspaceId, | 383 | scopeId: input.scopeId, |
| 376 | workspaceRoot: runtimeLocalWorkspace.workspace.workspaceRoot, | 384 | scopeRoot: runtimeLocalScope.scope.scopeRoot, |
| 377 | }), | 385 | }), |
| 378 | key: existing.key, | 386 | key: existing.key, |
| 379 | policyConfig: policies[existing.key]!, | 387 | policyConfig: policies[existing.key]!, |
| 380 | state: workspaceState.policies[existing.key], | 388 | state: scopeState.policies[existing.key], |
| 381 | }); | 389 | }); |
| 382 | }); | 390 | }); |
| 383 | 391 | ||
| 384 | export const removePolicy = (input: { | 392 | export const removePolicy = (input: { |
| 385 | workspaceId: WorkspaceId; | 393 | scopeId: ScopeId; |
| 386 | policyId: PolicyId; | 394 | policyId: PolicyId; |
| 387 | }) => | 395 | }) => |
| 388 | Effect.gen(function* () { | 396 | Effect.gen(function* () { |
| 389 | const runtimeLocalWorkspace = yield* loadWorkspacePolicyContext( | 397 | const runtimeLocalScope = yield* loadScopePolicyContext( |
| 390 | policyOps.remove, | 398 | policyOps.remove, |
| 391 | input.workspaceId, | 399 | input.scopeId, |
| 392 | ); | 400 | ); |
| 393 | const workspaceConfigStore = yield* WorkspaceConfigStore; | 401 | const scopeConfigStore = yield* ScopeConfigStore; |
| 394 | const workspaceStateStore = yield* WorkspaceStateStore; | 402 | const scopeStateStore = yield* ScopeStateStore; |
| 395 | const localWorkspace = yield* loadRuntimeLocalWorkspacePolicies( | 403 | const localScope = yield* loadRuntimeLocalScopePolicies( |
| 396 | input.workspaceId, | 404 | input.scopeId, |
| 397 | ).pipe( | 405 | ).pipe( |
| 398 | Effect.mapError((cause) => | 406 | Effect.mapError((cause) => |
| 399 | policyOps.remove.unknownStorage( | 407 | policyOps.remove.unknownStorage( |
| 400 | cause, | 408 | cause, |
| 401 | "Failed loading local workspace policies", | 409 | "Failed loading local scope policies", |
| 402 | ), | 410 | ), |
| 403 | ), | 411 | ), |
| 404 | ); | 412 | ); |
| 405 | const existing = | 413 | const existing = |
| 406 | localWorkspace.policies.find( | 414 | localScope.policies.find( |
| 407 | (candidate) => candidate.id === input.policyId, | 415 | (candidate) => candidate.id === input.policyId, |
| 408 | ) ?? null; | 416 | ) ?? null; |
| 409 | if (existing === null) { | 417 | if (existing === null) { |
| @@ -411,23 +419,23 @@ export const removePolicy = (input: { · 1 unmodified line | |||
| 411 | } | 419 | } |
| 412 | 420 | ||
| 413 | const projectConfig = cloneJson( | 421 | const projectConfig = cloneJson( |
| 414 | localWorkspace.loadedConfig.projectConfig ?? {}, | 422 | localScope.loadedConfig.projectConfig ?? {}, |
| 415 | ); | 423 | ); |
| 416 | const policies = { ...projectConfig.policies }; | 424 | const policies = { ...projectConfig.policies }; |
| 417 | delete policies[existing.key]; | 425 | delete policies[existing.key]; |
| 418 | 426 | ||
| 419 | const { [existing.key]: _removedPolicy, ...remainingPolicies } = | 427 | const { [existing.key]: _removedPolicy, ...remainingPolicies } = |
| 420 | localWorkspace.workspaceState.policies; | 428 | localScope.scopeState.policies; |
| 421 | yield* writeLocalPolicyFiles({ | 429 | yield* writeLocalPolicyFiles({ |
| 422 | operation: policyOps.remove, | 430 | operation: policyOps.remove, |
| 423 | workspaceConfigStore, | 431 | scopeConfigStore, |
| 424 | workspaceStateStore, | 432 | scopeStateStore, |
| 425 | projectConfig: { | 433 | projectConfig: { |
| 426 | ...projectConfig, | 434 | ...projectConfig, |
| 427 | policies, | 435 | policies, |
| 428 | }, | 436 | }, |
| 429 | workspaceState: { | 437 | scopeState: { |
| 430 | ...localWorkspace.workspaceState, | 438 | ...localScope.scopeState, |
| 431 | policies: remainingPolicies, | 439 | policies: remainingPolicies, |
| 432 | }, | 440 | }, |
| 433 | }); | 441 | }); |
| @@ -1,6 +1,8 @@ | |||
| 1 | import type { OAuthClientProvider } from "@modelcontextprotocol/sdk/client/auth.js"; | 1 | import type { |
| 2 | OAuthClientProvider, | ||
| 3 | } from "@modelcontextprotocol/sdk/client/auth.js"; | ||
| 2 | import { | 4 | import { |
| 3 | type AccountId, | 5 | type ScopeId, |
| 4 | AuthGrantSetJsonSchema, | 6 | AuthGrantSetJsonSchema, |
| 5 | McpOAuthAuthArtifactConfigJsonSchema, | 7 | McpOAuthAuthArtifactConfigJsonSchema, |
| 6 | McpOAuthAuthArtifactKind, | 8 | McpOAuthAuthArtifactKind, |
| @@ -35,8 +37,10 @@ import * as Schema from "effect/Schema"; · 28 unmodified lines | |||
| 35 | import type { | 37 | import type { |
| 36 | ResolveSecretMaterial, | 38 | ResolveSecretMaterial, |
| 37 | SecretMaterialResolveContext, | 39 | SecretMaterialResolveContext, |
| 38 | } from "../workspace/secret-material-providers"; | 40 | } from "../scope/secret-material-providers"; |
| 39 | import { runtimeEffectError } from "../effect-errors"; | 41 | import { |
| 42 | runtimeEffectError, | ||
| 43 | } from "../effect-errors"; | ||
| 40 | 44 | ||
| 41 | export type ResolvedSourceAuthMaterial = { | 45 | export type ResolvedSourceAuthMaterial = { |
| 42 | placements: ReadonlyArray<RequestPlacement>; | 46 | placements: ReadonlyArray<RequestPlacement>; |
| @@ -154,7 +158,7 @@ export const authArtifactFromSourceAuth = (input: { · 111 unmodified lines | |||
| 154 | source: Source; | 158 | source: Source; |
| 155 | auth: SourceAuth; | 159 | auth: SourceAuth; |
| 156 | slot: CredentialSlot; | 160 | slot: CredentialSlot; |
| 157 | actorAccountId?: AccountId | null; | 161 | actorScopeId?: ScopeId | null; |
| 158 | existingAuthArtifactId?: AuthArtifact["id"] | null; | 162 | existingAuthArtifactId?: AuthArtifact["id"] | null; |
| 159 | }): AuthArtifact | null => { | 163 | }): AuthArtifact | null => { |
| 160 | if (input.auth.kind === "none") { | 164 | if (input.auth.kind === "none") { |
| @@ -170,9 +174,9 @@ export const authArtifactFromSourceAuth = (input: { · 9 unmodified lines | |||
| 170 | if (input.auth.kind === "bearer") { | 174 | if (input.auth.kind === "bearer") { |
| 171 | return { | 175 | return { |
| 172 | id, | 176 | id, |
| 173 | workspaceId: input.source.workspaceId, | 177 | scopeId: input.source.scopeId, |
| 174 | sourceId: input.source.id, | 178 | sourceId: input.source.id, |
| 175 | actorAccountId: input.actorAccountId ?? null, | 179 | actorScopeId: input.actorScopeId ?? null, |
| 176 | slot: input.slot, | 180 | slot: input.slot, |
| 177 | artifactKind: StaticBearerAuthArtifactKind, | 181 | artifactKind: StaticBearerAuthArtifactKind, |
| 178 | configJson: encodeStaticBearerAuthArtifactConfig({ | 182 | configJson: encodeStaticBearerAuthArtifactConfig({ |
| @@ -189,9 +193,9 @@ export const authArtifactFromSourceAuth = (input: { · 10 unmodified lines | |||
| 189 | if (input.auth.kind === "oauth2_authorized_user") { | 193 | if (input.auth.kind === "oauth2_authorized_user") { |
| 190 | return { | 194 | return { |
| 191 | id, | 195 | id, |
| 192 | workspaceId: input.source.workspaceId, | 196 | scopeId: input.source.scopeId, |
| 193 | sourceId: input.source.id, | 197 | sourceId: input.source.id, |
| 194 | actorAccountId: input.actorAccountId ?? null, | 198 | actorScopeId: input.actorScopeId ?? null, |
| 195 | slot: input.slot, | 199 | slot: input.slot, |
| 196 | artifactKind: RefreshableOAuth2AuthorizedUserAuthArtifactKind, | 200 | artifactKind: RefreshableOAuth2AuthorizedUserAuthArtifactKind, |
| 197 | configJson: encodeRefreshableOAuth2AuthorizedUserAuthArtifactConfig({ | 201 | configJson: encodeRefreshableOAuth2AuthorizedUserAuthArtifactConfig({ |
| @@ -212,9 +216,9 @@ export const authArtifactFromSourceAuth = (input: { · 14 unmodified lines | |||
| 212 | if (input.auth.kind === "provider_grant_ref") { | 216 | if (input.auth.kind === "provider_grant_ref") { |
| 213 | return { | 217 | return { |
| 214 | id, | 218 | id, |
| 215 | workspaceId: input.source.workspaceId, | 219 | scopeId: input.source.scopeId, |
| 216 | sourceId: input.source.id, | 220 | sourceId: input.source.id, |
| 217 | actorAccountId: input.actorAccountId ?? null, | 221 | actorScopeId: input.actorScopeId ?? null, |
| 218 | slot: input.slot, | 222 | slot: input.slot, |
| 219 | artifactKind: ProviderGrantRefAuthArtifactKind, | 223 | artifactKind: ProviderGrantRefAuthArtifactKind, |
| 220 | configJson: encodeProviderGrantRefAuthArtifactConfig({ | 224 | configJson: encodeProviderGrantRefAuthArtifactConfig({ |
| @@ -233,9 +237,9 @@ export const authArtifactFromSourceAuth = (input: { · 12 unmodified lines | |||
| 233 | if (input.auth.kind === "mcp_oauth") { | 237 | if (input.auth.kind === "mcp_oauth") { |
| 234 | return { | 238 | return { |
| 235 | id, | 239 | id, |
| 236 | workspaceId: input.source.workspaceId, | 240 | scopeId: input.source.scopeId, |
| 237 | sourceId: input.source.id, | 241 | sourceId: input.source.id, |
| 238 | actorAccountId: input.actorAccountId ?? null, | 242 | actorScopeId: input.actorScopeId ?? null, |
| 239 | slot: input.slot, | 243 | slot: input.slot, |
| 240 | artifactKind: McpOAuthAuthArtifactKind, | 244 | artifactKind: McpOAuthAuthArtifactKind, |
| 241 | configJson: encodeMcpOAuthAuthArtifactConfig({ | 245 | configJson: encodeMcpOAuthAuthArtifactConfig({ |
| @@ -259,9 +263,9 @@ export const authArtifactFromSourceAuth = (input: { · 17 unmodified lines | |||
| 259 | 263 | ||
| 260 | return { | 264 | return { |
| 261 | id, | 265 | id, |
| 262 | workspaceId: input.source.workspaceId, | 266 | scopeId: input.source.scopeId, |
| 263 | sourceId: input.source.id, | 267 | sourceId: input.source.id, |
| 264 | actorAccountId: input.actorAccountId ?? null, | 268 | actorScopeId: input.actorScopeId ?? null, |
| 265 | slot: input.slot, | 269 | slot: input.slot, |
| 266 | artifactKind: StaticOAuth2AuthArtifactKind, | 270 | artifactKind: StaticOAuth2AuthArtifactKind, |
| 267 | configJson: encodeStaticOAuth2AuthArtifactConfig({ | 271 | configJson: encodeStaticOAuth2AuthArtifactConfig({ |
| @@ -16,18 +16,31 @@ import { · 15 unmodified lines | |||
| 16 | import * as Effect from "effect/Effect"; | 16 | import * as Effect from "effect/Effect"; |
| 17 | import * as Option from "effect/Option"; | 17 | import * as Option from "effect/Option"; |
| 18 | 18 | ||
| 19 | import type { ExecutorStateStoreShape } from "../executor-state-store"; | 19 | import type { |
| 20 | import { resolveAuthArtifactMaterial, type ResolvedSourceAuthMaterial } from "./auth-artifacts"; | 20 | ExecutorStateStoreShape, |
| 21 | } from "../executor-state-store"; | ||
| 22 | import { | ||
| 23 | resolveAuthArtifactMaterial, | ||
| 24 | type ResolvedSourceAuthMaterial, | ||
| 25 | } from "./auth-artifacts"; | ||
| 21 | import { | 26 | import { |
| 22 | type DeleteSecretMaterial, | 27 | type DeleteSecretMaterial, |
| 23 | type ResolveSecretMaterial, | 28 | type ResolveSecretMaterial, |
| 24 | type SecretMaterialResolveContext, | 29 | type SecretMaterialResolveContext, |
| 25 | type StoreSecretMaterial, | 30 | type StoreSecretMaterial, |
| 26 | } from "../workspace/secret-material-providers"; | 31 | } from "../scope/secret-material-providers"; |
| 27 | import { refreshOAuth2AccessToken } from "./oauth2-pkce"; | 32 | import { |
| 28 | import type { OAuth2TokenResponse } from "./oauth2-pkce"; | 33 | refreshOAuth2AccessToken, |
| 29 | import { createPersistedMcpAuthProvider } from "./mcp-auth-provider"; | 34 | } from "./oauth2-pkce"; |
| 30 | import { runtimeEffectError } from "../effect-errors"; | 35 | import type { |
| 36 | OAuth2TokenResponse, | ||
| 37 | } from "./oauth2-pkce"; | ||
| 38 | import { | ||
| 39 | createPersistedMcpAuthProvider, | ||
| 40 | } from "./mcp-auth-provider"; | ||
| 41 | import { | ||
| 42 | runtimeEffectError, | ||
| 43 | } from "../effect-errors"; | ||
| 31 | 44 | ||
| 32 | const LEASE_REFRESH_SKEW_MS = 60_000; | 45 | const LEASE_REFRESH_SKEW_MS = 60_000; |
| 33 | 46 | ||
| @@ -134,9 +147,9 @@ const refreshRefreshableOauth2AuthorizedUserArtifact = (input: { · 100 unmodified lines | |||
| 134 | const nextLease: AuthLease = { | 147 | const nextLease: AuthLease = { |
| 135 | id: input.lease?.id ?? AuthLeaseIdSchema.make(`auth_lease_${crypto.randomUUID()}`), | 148 | id: input.lease?.id ?? AuthLeaseIdSchema.make(`auth_lease_${crypto.randomUUID()}`), |
| 136 | authArtifactId: input.artifact.id, | 149 | authArtifactId: input.artifact.id, |
| 137 | workspaceId: input.artifact.workspaceId, | 150 | scopeId: input.artifact.scopeId, |
| 138 | sourceId: input.artifact.sourceId, | 151 | sourceId: input.artifact.sourceId, |
| 139 | actorAccountId: input.artifact.actorAccountId, | 152 | actorScopeId: input.artifact.actorScopeId, |
| 140 | slot: input.artifact.slot, | 153 | slot: input.artifact.slot, |
| 141 | placementsTemplateJson: encodeLeasePlacementTemplatesJson([ | 154 | placementsTemplateJson: encodeLeasePlacementTemplatesJson([ |
| 142 | { | 155 | { |
| @@ -169,7 +182,7 @@ const refreshRefreshableOauth2AuthorizedUserArtifact = (input: { · 26 unmodified lines | |||
| 169 | return nextLease; | 182 | return nextLease; |
| 170 | }); | 183 | }); |
| 171 | 184 | ||
| 172 | const workspaceOauthClientSecretRef = (input: { | 185 | const scopeOauthClientSecretRef = (input: { |
| 173 | clientSecretProviderId: string | null; | 186 | clientSecretProviderId: string | null; |
| 174 | clientSecretHandle: string | null; | 187 | clientSecretHandle: string | null; |
| 175 | }): SecretRef | null => | 188 | }): SecretRef | null => |
| @@ -212,9 +225,9 @@ const refreshProviderGrantRefArtifact = (input: { · 36 unmodified lines | |||
| 212 | } | 225 | } |
| 213 | const grant = grantOption.value; | 226 | const grant = grantOption.value; |
| 214 | 227 | ||
| 215 | const oauthClientOption = yield* input.executorState.workspaceOauthClients.getById(grant.oauthClientId); | 228 | const oauthClientOption = yield* input.executorState.scopeOauthClients.getById(grant.oauthClientId); |
| 216 | if (Option.isNone(oauthClientOption)) { | 229 | if (Option.isNone(oauthClientOption)) { |
| 217 | return yield* runtimeEffectError("auth/auth-leases", `Workspace OAuth client not found: ${grant.oauthClientId}`); | 230 | return yield* runtimeEffectError("auth/auth-leases", `Scope OAuth client not found: ${grant.oauthClientId}`); |
| 218 | } | 231 | } |
| 219 | const oauthClient = oauthClientOption.value; | 232 | const oauthClient = oauthClientOption.value; |
| 220 | 233 | ||
| @@ -222,7 +235,7 @@ const refreshProviderGrantRefArtifact = (input: { · 1 unmodified line | |||
| 222 | ref: grant.refreshToken, | 235 | ref: grant.refreshToken, |
| 223 | context: input.context, | 236 | context: input.context, |
| 224 | }); | 237 | }); |
| 225 | const clientSecretRef = workspaceOauthClientSecretRef(oauthClient); | 238 | const clientSecretRef = scopeOauthClientSecretRef(oauthClient); |
| 226 | const clientSecret = clientSecretRef | 239 | const clientSecret = clientSecretRef |
| 227 | ? yield* input.resolveSecretMaterial({ | 240 | ? yield* input.resolveSecretMaterial({ |
| 228 | ref: clientSecretRef, | 241 | ref: clientSecretRef, |
| @@ -277,9 +290,9 @@ const refreshProviderGrantRefArtifact = (input: { · 48 unmodified lines | |||
| 277 | const nextLease: AuthLease = { | 290 | const nextLease: AuthLease = { |
| 278 | id: input.lease?.id ?? AuthLeaseIdSchema.make(`auth_lease_${crypto.randomUUID()}`), | 291 | id: input.lease?.id ?? AuthLeaseIdSchema.make(`auth_lease_${crypto.randomUUID()}`), |
| 279 | authArtifactId: input.artifact.id, | 292 | authArtifactId: input.artifact.id, |
| 280 | workspaceId: input.artifact.workspaceId, | 293 | scopeId: input.artifact.scopeId, |
| 281 | sourceId: input.artifact.sourceId, | 294 | sourceId: input.artifact.sourceId, |
| 282 | actorAccountId: input.artifact.actorAccountId, | 295 | actorScopeId: input.artifact.actorScopeId, |
| 283 | slot: input.artifact.slot, | 296 | slot: input.artifact.slot, |
| 284 | placementsTemplateJson: encodeLeasePlacementTemplatesJson([ | 297 | placementsTemplateJson: encodeLeasePlacementTemplatesJson([ |
| 285 | { | 298 | { |
| @@ -363,9 +376,9 @@ export const upsertOauth2AuthorizedUserLeaseFromTokenResponse = (input: { · 77 unmodified lines | |||
| 363 | const nextLease: AuthLease = { | 376 | const nextLease: AuthLease = { |
| 364 | id: existingLease?.id ?? AuthLeaseIdSchema.make(`auth_lease_${crypto.randomUUID()}`), | 377 | id: existingLease?.id ?? AuthLeaseIdSchema.make(`auth_lease_${crypto.randomUUID()}`), |
| 365 | authArtifactId: input.artifact.id, | 378 | authArtifactId: input.artifact.id, |
| 366 | workspaceId: input.artifact.workspaceId, | 379 | scopeId: input.artifact.scopeId, |
| 367 | sourceId: input.artifact.sourceId, | 380 | sourceId: input.artifact.sourceId, |
| 368 | actorAccountId: input.artifact.actorAccountId, | 381 | actorScopeId: input.artifact.actorScopeId, |
| 369 | slot: input.artifact.slot, | 382 | slot: input.artifact.slot, |
| 370 | placementsTemplateJson: encodeLeasePlacementTemplatesJson([ | 383 | placementsTemplateJson: encodeLeasePlacementTemplatesJson([ |
| 371 | { | 384 | { |
| @@ -20,13 +20,15 @@ import { · 19 unmodified lines | |||
| 20 | import * as Effect from "effect/Effect"; | 20 | import * as Effect from "effect/Effect"; |
| 21 | import * as Schema from "effect/Schema"; | 21 | import * as Schema from "effect/Schema"; |
| 22 | 22 | ||
| 23 | import type { ExecutorStateStoreShape } from "../executor-state-store"; | 23 | import type { |
| 24 | ExecutorStateStoreShape, | ||
| 25 | } from "../executor-state-store"; | ||
| 24 | import { | 26 | import { |
| 25 | type DeleteSecretMaterial, | 27 | type DeleteSecretMaterial, |
| 26 | type ResolveSecretMaterial, | 28 | type ResolveSecretMaterial, |
| 27 | type SecretMaterialResolveContext, | 29 | type SecretMaterialResolveContext, |
| 28 | type StoreSecretMaterial, | 30 | type StoreSecretMaterial, |
| 29 | } from "../workspace/secret-material-providers"; | 31 | } from "../scope/secret-material-providers"; |
| 30 | 32 | ||
| 31 | const encodeMcpOAuthAuthArtifactConfig = Schema.encodeSync( | 33 | const encodeMcpOAuthAuthArtifactConfig = Schema.encodeSync( |
| 32 | McpOAuthAuthArtifactConfigJsonSchema, | 34 | McpOAuthAuthArtifactConfigJsonSchema, |
| @@ -1,9 +1,17 @@ | |||
| 1 | import { createServer } from "node:http"; | 1 | import { |
| 2 | createServer, | ||
| 3 | } from "node:http"; | ||
| 2 | 4 | ||
| 3 | import { describe, expect, it } from "@effect/vitest"; | 5 | import { |
| 6 | describe, | ||
| 7 | expect, | ||
| 8 | it, | ||
| 9 | } from "@effect/vitest"; | ||
| 4 | import * as Effect from "effect/Effect"; | 10 | import * as Effect from "effect/Effect"; |
| 5 | 11 | ||
| 6 | import { startOauthLoopbackRedirectServer } from "./oauth-loopback"; | 12 | import { |
| 13 | startOauthLoopbackRedirectServer, | ||
| 14 | } from "./oauth-loopback"; | ||
| 7 | 15 | ||
| 8 | const toError = (cause: unknown): Error => | 16 | const toError = (cause: unknown): Error => |
| 9 | cause instanceof Error ? cause : new Error(String(cause)); | 17 | cause instanceof Error ? cause : new Error(String(cause)); |
| @@ -1,4 +1,6 @@ | |||
| 1 | import { createServer } from "node:http"; | 1 | import { |
| 2 | createServer, | ||
| 3 | } from "node:http"; | ||
| 2 | 4 | ||
| 3 | import * as Effect from "effect/Effect"; | 5 | import * as Effect from "effect/Effect"; |
| 4 | 6 | ||
| @@ -1,7 +1,7 @@ | |||
| 1 | import type { | 1 | import type { |
| 2 | AuthArtifact, | 2 | AuthArtifact, |
| 3 | ProviderAuthGrant, | 3 | ProviderAuthGrant, |
| 4 | WorkspaceId, | 4 | ScopeId, |
| 5 | } from "#schema"; | 5 | } from "#schema"; |
| 6 | import { | 6 | import { |
| 7 | decodeProviderGrantRefAuthArtifactConfig, | 7 | decodeProviderGrantRefAuthArtifactConfig, |
| @@ -11,8 +11,10 @@ import * as Option from "effect/Option"; · 3 unmodified lines | |||
| 11 | 11 | ||
| 12 | import { | 12 | import { |
| 13 | type DeleteSecretMaterial, | 13 | type DeleteSecretMaterial, |
| 14 | } from "../workspace/secret-material-providers"; | 14 | } from "../scope/secret-material-providers"; |
| 15 | import type { ExecutorStateStoreShape } from "../executor-state-store"; | 15 | import type { |
| 16 | ExecutorStateStoreShape, | ||
| 17 | } from "../executor-state-store"; | ||
| 16 | 18 | ||
| 17 | const providerGrantRefFromArtifact = ( | 19 | const providerGrantRefFromArtifact = ( |
| 18 | artifact: Pick<AuthArtifact, "artifactKind" | "configJson">, | 20 | artifact: Pick<AuthArtifact, "artifactKind" | "configJson">, |
| @@ -24,11 +26,11 @@ export const providerGrantIdFromArtifact = ( · 5 unmodified lines | |||
| 24 | providerGrantRefFromArtifact(artifact)?.grantId ?? null; | 26 | providerGrantRefFromArtifact(artifact)?.grantId ?? null; |
| 25 | 27 | ||
| 26 | export const listProviderGrantRefArtifacts = (executorState: ExecutorStateStoreShape, input: { | 28 | export const listProviderGrantRefArtifacts = (executorState: ExecutorStateStoreShape, input: { |
| 27 | workspaceId: WorkspaceId; | 29 | scopeId: ScopeId; |
| 28 | grantId?: ProviderAuthGrant["id"] | null; | 30 | grantId?: ProviderAuthGrant["id"] | null; |
| 29 | }): Effect.Effect<readonly AuthArtifact[], Error, never> => | 31 | }): Effect.Effect<readonly AuthArtifact[], Error, never> => |
| 30 | Effect.map( | 32 | Effect.map( |
| 31 | executorState.authArtifacts.listByWorkspaceId(input.workspaceId), | 33 | executorState.authArtifacts.listByScopeId(input.scopeId), |
| 32 | (artifacts) => | 34 | (artifacts) => |
| 33 | artifacts.filter((artifact) => { | 35 | artifacts.filter((artifact) => { |
| 34 | const grantId = providerGrantIdFromArtifact(artifact); | 36 | const grantId = providerGrantIdFromArtifact(artifact); |
| @@ -54,7 +56,7 @@ export const clearProviderGrantOrphanedAt = (executorState: ExecutorStateStoreSh · 19 unmodified lines | |||
| 54 | }); | 56 | }); |
| 55 | 57 | ||
| 56 | export const markProviderGrantOrphanedIfUnused = (executorState: ExecutorStateStoreShape, input: { | 58 | export const markProviderGrantOrphanedIfUnused = (executorState: ExecutorStateStoreShape, input: { |
| 57 | workspaceId: WorkspaceId; | 59 | scopeId: ScopeId; |
| 58 | grantId: ProviderAuthGrant["id"]; | 60 | grantId: ProviderAuthGrant["id"]; |
| 59 | }): Effect.Effect<boolean, Error, never> => | 61 | }): Effect.Effect<boolean, Error, never> => |
| 60 | Effect.gen(function* () { | 62 | Effect.gen(function* () { |
| @@ -64,7 +66,7 @@ export const markProviderGrantOrphanedIfUnused = (executorState: ExecutorStateSt · 3 unmodified lines | |||
| 64 | } | 66 | } |
| 65 | 67 | ||
| 66 | const grantOption = yield* executorState.providerAuthGrants.getById(input.grantId); | 68 | const grantOption = yield* executorState.providerAuthGrants.getById(input.grantId); |
| 67 | if (Option.isNone(grantOption) || grantOption.value.workspaceId !== input.workspaceId) { | 69 | if (Option.isNone(grantOption) || grantOption.value.scopeId !== input.scopeId) { |
| 68 | return false; | 70 | return false; |
| 69 | } | 71 | } |
| 70 | 72 | ||
| @@ -1,19 +1,25 @@ | |||
| 1 | import { describe, expect, it } from "@effect/vitest"; | 1 | import { |
| 2 | describe, | ||
| 3 | expect, | ||
| 4 | it, | ||
| 5 | } from "@effect/vitest"; | ||
| 2 | import * as Effect from "effect/Effect"; | 6 | import * as Effect from "effect/Effect"; |
| 3 | import * as Option from "effect/Option"; | 7 | import * as Option from "effect/Option"; |
| 4 | 8 | ||
| 5 | import { | 9 | import { |
| 6 | AuthArtifactIdSchema, | 10 | AuthArtifactIdSchema, |
| 7 | SourceIdSchema, | 11 | SourceIdSchema, |
| 8 | WorkspaceIdSchema, | 12 | ScopeIdSchema, |
| 9 | type Source, | 13 | type Source, |
| 10 | } from "#schema"; | 14 | } from "#schema"; |
| 11 | 15 | ||
| 12 | import { resolveSourceAuthMaterialWithDeps } from "./source-auth-material"; | 16 | import { |
| 17 | resolveSourceAuthMaterialWithDeps, | ||
| 18 | } from "./source-auth-material"; | ||
| 13 | 19 | ||
| 14 | const makeSource = (overrides: Partial<Source> = {}): Source => ({ | 20 | const makeSource = (overrides: Partial<Source> = {}): Source => ({ |
| 15 | id: SourceIdSchema.make("src_tool_artifacts"), | 21 | id: SourceIdSchema.make("src_tool_artifacts"), |
| 16 | workspaceId: WorkspaceIdSchema.make("ws_tool_artifacts"), | 22 | scopeId: ScopeIdSchema.make("ws_tool_artifacts"), |
| 17 | name: "GitHub", | 23 | name: "GitHub", |
| 18 | kind: "openapi", | 24 | kind: "openapi", |
| 19 | endpoint: "https://api.github.com", | 25 | endpoint: "https://api.github.com", |
| @@ -176,16 +182,16 @@ describe("source-auth-material", () => { · 156 unmodified lines | |||
| 176 | }, | 182 | }, |
| 177 | auth: { kind: "none" }, | 183 | auth: { kind: "none" }, |
| 178 | }), | 184 | }), |
| 179 | actorAccountId: null, | 185 | actorScopeId: null, |
| 180 | executorState: { | 186 | executorState: { |
| 181 | authArtifacts: { | 187 | authArtifacts: { |
| 182 | getByWorkspaceSourceAndActor: () => | 188 | getByScopeSourceAndActor: () => |
| 183 | Effect.succeed( | 189 | Effect.succeed( |
| 184 | Option.some({ | 190 | Option.some({ |
| 185 | id: AuthArtifactIdSchema.make("auth_artifact_mcp"), | 191 | id: AuthArtifactIdSchema.make("auth_artifact_mcp"), |
| 186 | workspaceId: WorkspaceIdSchema.make("ws_tool_artifacts"), | 192 | scopeId: ScopeIdSchema.make("ws_tool_artifacts"), |
| 187 | sourceId: SourceIdSchema.make("src_tool_artifacts"), | 193 | sourceId: SourceIdSchema.make("src_tool_artifacts"), |
| 188 | actorAccountId: null, | 194 | actorScopeId: null, |
| 189 | slot: "runtime", | 195 | slot: "runtime", |
| 190 | artifactKind: "mcp_oauth", | 196 | artifactKind: "mcp_oauth", |
| 191 | configJson: JSON.stringify({ | 197 | configJson: JSON.stringify({ |
| @@ -1,5 +1,5 @@ | |||
| 1 | import type { | 1 | import type { |
| 2 | AccountId, | 2 | ScopeId, |
| 3 | CredentialSlot, | 3 | CredentialSlot, |
| 4 | Source, | 4 | Source, |
| 5 | SourceAuth, | 5 | SourceAuth, |
| @@ -9,25 +9,32 @@ import * as Effect from "effect/Effect"; · 3 unmodified lines | |||
| 9 | import * as Layer from "effect/Layer"; | 9 | import * as Layer from "effect/Layer"; |
| 10 | import * as Option from "effect/Option"; | 10 | import * as Option from "effect/Option"; |
| 11 | 11 | ||
| 12 | import { ExecutorStateStore, type ExecutorStateStoreShape } from "../executor-state-store"; | 12 | import { |
| 13 | ExecutorStateStore, | ||
| 14 | type ExecutorStateStoreShape, | ||
| 15 | } from "../executor-state-store"; | ||
| 13 | import { | 16 | import { |
| 14 | authArtifactFromSourceAuth, | 17 | authArtifactFromSourceAuth, |
| 15 | resolveAuthArtifactMaterial, | 18 | resolveAuthArtifactMaterial, |
| 16 | type ResolvedSourceAuthMaterial, | 19 | type ResolvedSourceAuthMaterial, |
| 17 | } from "./auth-artifacts"; | 20 | } from "./auth-artifacts"; |
| 18 | import { resolveAuthArtifactMaterialWithLeases } from "./auth-leases"; | 21 | import { |
| 22 | resolveAuthArtifactMaterialWithLeases, | ||
| 23 | } from "./auth-leases"; | ||
| 19 | import type { | 24 | import type { |
| 20 | DeleteSecretMaterial, | 25 | DeleteSecretMaterial, |
| 21 | ResolveSecretMaterial, | 26 | ResolveSecretMaterial, |
| 22 | SecretMaterialResolveContext, | 27 | SecretMaterialResolveContext, |
| 23 | StoreSecretMaterial, | 28 | StoreSecretMaterial, |
| 24 | } from "../workspace/secret-material-providers"; | 29 | } from "../scope/secret-material-providers"; |
| 25 | import { | 30 | import { |
| 26 | SecretMaterialDeleterService, | 31 | SecretMaterialDeleterService, |
| 27 | SecretMaterialResolverService, | 32 | SecretMaterialResolverService, |
| 28 | SecretMaterialStorerService, | 33 | SecretMaterialStorerService, |
| 29 | } from "../workspace/secret-material-providers"; | 34 | } from "../scope/secret-material-providers"; |
| 30 | import { runtimeEffectError } from "../effect-errors"; | 35 | import { |
| 36 | runtimeEffectError, | ||
| 37 | } from "../effect-errors"; | ||
| 31 | 38 | ||
| 32 | const authForSlot = (input: { | 39 | const authForSlot = (input: { |
| 33 | source: Source; | 40 | source: Source; |
| @@ -52,7 +59,7 @@ export type RuntimeSourceAuthMaterialShape = { · 18 unmodified lines | |||
| 52 | resolve: (input: { | 59 | resolve: (input: { |
| 53 | source: Source; | 60 | source: Source; |
| 54 | slot?: CredentialSlot; | 61 | slot?: CredentialSlot; |
| 55 | actorAccountId?: AccountId | null; | 62 | actorScopeId?: ScopeId | null; |
| 56 | context?: SecretMaterialResolveContext; | 63 | context?: SecretMaterialResolveContext; |
| 57 | }) => Effect.Effect<ResolvedSourceAuthMaterial, Error, never>; | 64 | }) => Effect.Effect<ResolvedSourceAuthMaterial, Error, never>; |
| 58 | }; | 65 | }; |
| @@ -64,7 +71,7 @@ export class RuntimeSourceAuthMaterialService extends Context.Tag( · 5 unmodified lines | |||
| 64 | export const resolveSourceAuthMaterialWithDeps = (input: { | 71 | export const resolveSourceAuthMaterialWithDeps = (input: { |
| 65 | source: Source; | 72 | source: Source; |
| 66 | slot?: CredentialSlot; | 73 | slot?: CredentialSlot; |
| 67 | actorAccountId?: AccountId | null; | 74 | actorScopeId?: ScopeId | null; |
| 68 | executorState?: ExecutorStateStoreShape; | 75 | executorState?: ExecutorStateStoreShape; |
| 69 | resolveSecretMaterial: ResolveSecretMaterial; | 76 | resolveSecretMaterial: ResolveSecretMaterial; |
| 70 | storeSecretMaterial?: StoreSecretMaterial; | 77 | storeSecretMaterial?: StoreSecretMaterial; |
| @@ -81,10 +88,10 @@ export const resolveSourceAuthMaterialWithDeps = (input: { · 10 unmodified lines | |||
| 81 | : [slot] satisfies ReadonlyArray<CredentialSlot>; | 88 | : [slot] satisfies ReadonlyArray<CredentialSlot>; |
| 82 | 89 | ||
| 83 | for (const candidateSlot of candidateSlots) { | 90 | for (const candidateSlot of candidateSlots) { |
| 84 | const artifactOption = yield* input.executorState.authArtifacts.getByWorkspaceSourceAndActor({ | 91 | const artifactOption = yield* input.executorState.authArtifacts.getByScopeSourceAndActor({ |
| 85 | workspaceId: input.source.workspaceId, | 92 | scopeId: input.source.scopeId, |
| 86 | sourceId: input.source.id, | 93 | sourceId: input.source.id, |
| 87 | actorAccountId: input.actorAccountId ?? null, | 94 | actorScopeId: input.actorScopeId ?? null, |
| 88 | slot: candidateSlot, | 95 | slot: candidateSlot, |
| 89 | }); | 96 | }); |
| 90 | 97 | ||
| @@ -108,7 +115,7 @@ export const resolveSourceAuthMaterialWithDeps = (input: { · 17 unmodified lines | |||
| 108 | slot, | 115 | slot, |
| 109 | }), | 116 | }), |
| 110 | slot, | 117 | slot, |
| 111 | actorAccountId: input.actorAccountId ?? null, | 118 | actorScopeId: input.actorScopeId ?? null, |
| 112 | }); | 119 | }); |
| 113 | 120 | ||
| 114 | if (input.executorState !== undefined) { | 121 | if (input.executorState !== undefined) { |
| @@ -140,7 +147,7 @@ export const resolveSourceAuthMaterialWithDeps = (input: { · 25 unmodified lines | |||
| 140 | export const resolveSourceAuthMaterial = (input: { | 147 | export const resolveSourceAuthMaterial = (input: { |
| 141 | source: Source; | 148 | source: Source; |
| 142 | slot?: CredentialSlot; | 149 | slot?: CredentialSlot; |
| 143 | actorAccountId?: AccountId | null; | 150 | actorScopeId?: ScopeId | null; |
| 144 | context?: SecretMaterialResolveContext; | 151 | context?: SecretMaterialResolveContext; |
| 145 | }): Effect.Effect<ResolvedSourceAuthMaterial, Error, RuntimeSourceAuthMaterialService> => | 152 | }): Effect.Effect<ResolvedSourceAuthMaterial, Error, RuntimeSourceAuthMaterialService> => |
| 146 | Effect.flatMap(RuntimeSourceAuthMaterialService, (service) => service.resolve(input)); | 153 | Effect.flatMap(RuntimeSourceAuthMaterialService, (service) => service.resolve(input)); |
| @@ -1,7 +1,13 @@ | |||
| 1 | import { createHash } from "node:crypto"; | 1 | import { |
| 2 | createHash, | ||
| 3 | } from "node:crypto"; | ||
| 2 | 4 | ||
| 3 | import type { ProjectedCatalog } from "@executor/ir/catalog"; | 5 | import type { |
| 4 | import type { ShapeSymbolId } from "@executor/ir/ids"; | 6 | ProjectedCatalog, |
| 7 | } from "@executor/ir/catalog"; | ||
| 8 | import type { | ||
| 9 | ShapeSymbolId, | ||
| 10 | } from "@executor/ir/ids"; | ||
| 5 | import type { | 11 | import type { |
| 6 | CatalogV1, | 12 | CatalogV1, |
| 7 | DocumentationBlock, | 13 | DocumentationBlock, |
| @@ -1,4 +1,6 @@ | |||
| 1 | import { format } from "prettier/standalone"; | 1 | import { |
| 2 | format, | ||
| 3 | } from "prettier/standalone"; | ||
| 2 | import parserBabel from "prettier/plugins/babel"; | 4 | import parserBabel from "prettier/plugins/babel"; |
| 3 | import parserEstree from "prettier/plugins/estree"; | 5 | import parserEstree from "prettier/plugins/estree"; |
| 4 | import parserTypescript from "prettier/plugins/typescript"; | 6 | import parserTypescript from "prettier/plugins/typescript"; |
| @@ -1,15 +1,24 @@ | |||
| 1 | import type { | 1 | import type { |
| 2 | AccountId, | 2 | ScopeId, |
| 3 | Source, | 3 | Source, |
| 4 | WorkspaceId, | ||
| 5 | } from "#schema"; | 4 | } from "#schema"; |
| 6 | import * as Effect from "effect/Effect"; | 5 | import * as Effect from "effect/Effect"; |
| 7 | 6 | ||
| 8 | import { RuntimeLocalWorkspaceService } from "../../workspace/runtime-context"; | 7 | import { |
| 9 | import { SourceArtifactStore } from "../../workspace/storage"; | 8 | RuntimeLocalScopeService, |
| 10 | import { getSourceAdapterForSource } from "../../sources/source-adapters"; | 9 | } from "../../scope/runtime-context"; |
| 11 | import { RuntimeSourceStoreService } from "../../sources/source-store"; | 10 | import { |
| 12 | import { RuntimeSourceCatalogSyncService } from "./sync"; | 11 | SourceArtifactStore, |
| 12 | } from "../../scope/storage"; | ||
| 13 | import { | ||
| 14 | getSourceAdapterForSource, | ||
| 15 | } from "../../sources/source-adapters"; | ||
| 16 | import { | ||
| 17 | RuntimeSourceStoreService, | ||
| 18 | } from "../../sources/source-store"; | ||
| 19 | import { | ||
| 20 | RuntimeSourceCatalogSyncService, | ||
| 21 | } from "./sync"; | ||
| 13 | 22 | ||
| 14 | const shouldReconcileSource = (source: Source): boolean => | 23 | const shouldReconcileSource = (source: Source): boolean => |
| 15 | source.enabled | 24 | source.enabled |
| @@ -17,23 +26,23 @@ const shouldReconcileSource = (source: Source): boolean => · 1 unmodified line | |||
| 17 | && getSourceAdapterForSource(source).catalogKind !== "internal"; | 26 | && getSourceAdapterForSource(source).catalogKind !== "internal"; |
| 18 | 27 | ||
| 19 | export const reconcileMissingSourceCatalogArtifacts = (input: { | 28 | export const reconcileMissingSourceCatalogArtifacts = (input: { |
| 20 | workspaceId: WorkspaceId; | 29 | scopeId: ScopeId; |
| 21 | actorAccountId?: AccountId | null; | 30 | actorScopeId?: ScopeId | null; |
| 22 | }): Effect.Effect< | 31 | }): Effect.Effect< |
| 23 | void, | 32 | void, |
| 24 | Error, | 33 | Error, |
| 25 | | RuntimeLocalWorkspaceService | 34 | | RuntimeLocalScopeService |
| 26 | | SourceArtifactStore | 35 | | SourceArtifactStore |
| 27 | | RuntimeSourceStoreService | 36 | | RuntimeSourceStoreService |
| 28 | | RuntimeSourceCatalogSyncService | 37 | | RuntimeSourceCatalogSyncService |
| 29 | > => | 38 | > => |
| 30 | Effect.gen(function* () { | 39 | Effect.gen(function* () { |
| 31 | const runtimeLocalWorkspace = yield* RuntimeLocalWorkspaceService; | 40 | const runtimeLocalScope = yield* RuntimeLocalScopeService; |
| 32 | const sourceStore = yield* RuntimeSourceStoreService; | 41 | const sourceStore = yield* RuntimeSourceStoreService; |
| 33 | const sourceArtifactStore = yield* SourceArtifactStore; | 42 | const sourceArtifactStore = yield* SourceArtifactStore; |
| 34 | const sourceCatalogSync = yield* RuntimeSourceCatalogSyncService; | 43 | const sourceCatalogSync = yield* RuntimeSourceCatalogSyncService; |
| 35 | const sources = yield* sourceStore.loadSourcesInWorkspace(input.workspaceId, { | 44 | const sources = yield* sourceStore.loadSourcesInScope(input.scopeId, { |
| 36 | actorAccountId: input.actorAccountId, | 45 | actorScopeId: input.actorScopeId, |
| 37 | }); | 46 | }); |
| 38 | 47 | ||
| 39 | for (const source of sources) { | 48 | for (const source of sources) { |
| @@ -50,7 +59,7 @@ export const reconcileMissingSourceCatalogArtifacts = (input: { · 10 unmodified lines | |||
| 50 | 59 | ||
| 51 | yield* sourceCatalogSync.sync({ | 60 | yield* sourceCatalogSync.sync({ |
| 52 | source, | 61 | source, |
| 53 | actorAccountId: input.actorAccountId, | 62 | actorScopeId: input.actorScopeId, |
| 54 | }).pipe( | 63 | }).pipe( |
| 55 | Effect.catchAll(() => Effect.void), | 64 | Effect.catchAll(() => Effect.void), |
| 56 | ); | 65 | ); |
| @@ -58,7 +67,7 @@ export const reconcileMissingSourceCatalogArtifacts = (input: { · 1 unmodified line | |||
| 58 | }).pipe( | 67 | }).pipe( |
| 59 | Effect.withSpan("source.catalog.reconcile_missing", { | 68 | Effect.withSpan("source.catalog.reconcile_missing", { |
| 60 | attributes: { | 69 | attributes: { |
| 61 | "executor.workspace.id": input.workspaceId, | 70 | "executor.scope.id": input.scopeId, |
| 62 | }, | 71 | }, |
| 63 | }), | 72 | }), |
| 64 | ); | 73 | ); |
| @@ -1,4 +1,8 @@ | |||
| 1 | import { describe, expect, it } from "@effect/vitest"; | 1 | import { |
| 2 | describe, | ||
| 3 | expect, | ||
| 4 | it, | ||
| 5 | } from "@effect/vitest"; | ||
| 2 | import * as Effect from "effect/Effect"; | 6 | import * as Effect from "effect/Effect"; |
| 3 | 7 | ||
| 4 | import type { | 8 | import type { |
| @@ -10,7 +14,7 @@ import { · 5 unmodified lines | |||
| 10 | SourceCatalogIdSchema, | 14 | SourceCatalogIdSchema, |
| 11 | SourceCatalogRevisionIdSchema, | 15 | SourceCatalogRevisionIdSchema, |
| 12 | SourceIdSchema, | 16 | SourceIdSchema, |
| 13 | WorkspaceIdSchema, | 17 | ScopeIdSchema, |
| 14 | } from "#schema"; | 18 | } from "#schema"; |
| 15 | 19 | ||
| 16 | import { | 20 | import { |
| @@ -27,7 +31,10 @@ import { · 10 unmodified lines | |||
| 27 | ScopeIdSchema, | 31 | ScopeIdSchema, |
| 28 | ShapeSymbolIdSchema, | 32 | ShapeSymbolIdSchema, |
| 29 | } from "@executor/ir/ids"; | 33 | } from "@executor/ir/ids"; |
| 30 | import type { CatalogV1, ProvenanceRef } from "@executor/ir/model"; | 34 | import type { |
| 35 | CatalogV1, | ||
| 36 | ProvenanceRef, | ||
| 37 | } from "@executor/ir/model"; | ||
| 31 | import { | 38 | import { |
| 32 | createCatalogTypeProjector, | 39 | createCatalogTypeProjector, |
| 33 | formatTypeNameSegment, | 40 | formatTypeNameSegment, |
| @@ -274,7 +281,7 @@ const createLoadedCatalog = (options?: { · 240 unmodified lines | |||
| 274 | 281 | ||
| 275 | const source = { | 282 | const source = { |
| 276 | id: SourceIdSchema.make("src_linear"), | 283 | id: SourceIdSchema.make("src_linear"), |
| 277 | workspaceId: WorkspaceIdSchema.make("ws_linear"), | 284 | scopeId: ScopeIdSchema.make("ws_linear"), |
| 278 | name: "Linear", | 285 | name: "Linear", |
| 279 | kind: "graphql-schema", | 286 | kind: "graphql-schema", |
| 280 | endpoint: "https://api.linear.app/graphql", | 287 | endpoint: "https://api.linear.app/graphql", |
| @@ -294,7 +301,7 @@ const createLoadedCatalog = (options?: { · 13 unmodified lines | |||
| 294 | 301 | ||
| 295 | const sourceRecord = { | 302 | const sourceRecord = { |
| 296 | id: source.id, | 303 | id: source.id, |
| 297 | workspaceId: source.workspaceId, | 304 | scopeId: source.scopeId, |
| 298 | catalogId: SourceCatalogIdSchema.make("catalog_linear"), | 305 | catalogId: SourceCatalogIdSchema.make("catalog_linear"), |
| 299 | catalogRevisionId: SourceCatalogRevisionIdSchema.make("catalog_revision_linear"), | 306 | catalogRevisionId: SourceCatalogRevisionIdSchema.make("catalog_revision_linear"), |
| 300 | name: source.name, | 307 | name: source.name, |
| @@ -3,11 +3,10 @@ import { · 2 unmodified lines | |||
| 3 | type ToolDescriptor as CatalogToolDescriptor, | 3 | type ToolDescriptor as CatalogToolDescriptor, |
| 4 | } from "@executor/codemode-core"; | 4 | } from "@executor/codemode-core"; |
| 5 | import type { | 5 | import type { |
| 6 | AccountId, | 6 | ScopeId, |
| 7 | Source, | 7 | Source, |
| 8 | StoredSourceRecord, | 8 | StoredSourceRecord, |
| 9 | StoredSourceCatalogRevisionRecord, | 9 | StoredSourceCatalogRevisionRecord, |
| 10 | WorkspaceId, | ||
| 11 | } from "#schema"; | 10 | } from "#schema"; |
| 12 | import * as Context from "effect/Context"; | 11 | import * as Context from "effect/Context"; |
| 13 | import * as Effect from "effect/Effect"; | 12 | import * as Effect from "effect/Effect"; |
| @@ -19,7 +18,9 @@ import { · 5 unmodified lines | |||
| 19 | projectCatalogForAgentSdk, | 18 | projectCatalogForAgentSdk, |
| 20 | type ProjectedCatalog, | 19 | type ProjectedCatalog, |
| 21 | } from "@executor/ir/catalog"; | 20 | } from "@executor/ir/catalog"; |
| 22 | import type { ShapeSymbolId } from "@executor/ir/ids"; | 21 | import type { |
| 22 | ShapeSymbolId, | ||
| 23 | } from "@executor/ir/ids"; | ||
| 23 | import type { | 24 | import type { |
| 24 | Capability, | 25 | Capability, |
| 25 | CatalogSnapshotV1, | 26 | CatalogSnapshotV1, |
| @@ -27,7 +28,9 @@ import type { · 1 unmodified line | |||
| 27 | Executable, | 28 | Executable, |
| 28 | ShapeSymbol, | 29 | ShapeSymbol, |
| 29 | } from "@executor/ir/model"; | 30 | } from "@executor/ir/model"; |
| 30 | import { LocalSourceArtifactMissingError } from "../../workspace-errors"; | 31 | import { |
| 32 | LocalSourceArtifactMissingError, | ||
| 33 | } from "../../scope-errors"; | ||
| 31 | import { | 34 | import { |
| 32 | createCatalogTypeProjector, | 35 | createCatalogTypeProjector, |
| 33 | documentationComment, | 36 | documentationComment, |
| @@ -36,21 +39,27 @@ import { · 2 unmodified lines | |||
| 36 | shapeAllowsOmittedArgs, | 39 | shapeAllowsOmittedArgs, |
| 37 | type CatalogTypeProjector, | 40 | type CatalogTypeProjector, |
| 38 | } from "../catalog-typescript"; | 41 | } from "../catalog-typescript"; |
| 39 | import { formatWithPrettier } from "../prettier-format"; | ||
| 40 | import { | 42 | import { |
| 41 | RuntimeLocalWorkspaceService, | 43 | formatWithPrettier, |
| 42 | type RuntimeLocalWorkspaceState, | 44 | } from "../prettier-format"; |
| 43 | } from "../../workspace/runtime-context"; | 45 | import { |
| 44 | import type { LocalSourceArtifact } from "../../source-artifacts"; | 46 | RuntimeLocalScopeService, |
| 47 | type RuntimeLocalScopeState, | ||
| 48 | } from "../../scope/runtime-context"; | ||
| 49 | import type { | ||
| 50 | LocalSourceArtifact, | ||
| 51 | } from "../../source-artifacts"; | ||
| 45 | import { | 52 | import { |
| 46 | SourceArtifactStore, | 53 | SourceArtifactStore, |
| 47 | type SourceArtifactStoreShape, | 54 | type SourceArtifactStoreShape, |
| 48 | } from "../../workspace/storage"; | 55 | } from "../../scope/storage"; |
| 49 | import { | 56 | import { |
| 50 | RuntimeSourceStoreService, | 57 | RuntimeSourceStoreService, |
| 51 | type RuntimeSourceStore, | 58 | type RuntimeSourceStore, |
| 52 | } from "../../sources/source-store"; | 59 | } from "../../sources/source-store"; |
| 53 | import { runtimeEffectError } from "../../effect-errors"; | 60 | import { |
| 61 | runtimeEffectError, | ||
| 62 | } from "../../effect-errors"; | ||
| 54 | 63 | ||
| 55 | type CatalogImportMetadata = CatalogSnapshotV1["import"]; | 64 | type CatalogImportMetadata = CatalogSnapshotV1["import"]; |
| 56 | 65 | ||
| @@ -644,7 +653,7 @@ const sourceRecordFromCatalogArtifact = (input: { · 587 unmodified lines | |||
| 644 | }; | 653 | }; |
| 645 | }): StoredSourceRecord => ({ | 654 | }): StoredSourceRecord => ({ |
| 646 | id: input.source.id, | 655 | id: input.source.id, |
| 647 | workspaceId: input.source.workspaceId, | 656 | scopeId: input.source.scopeId, |
| 648 | catalogId: input.artifact.catalogId, | 657 | catalogId: input.artifact.catalogId, |
| 649 | catalogRevisionId: input.artifact.revision.id, | 658 | catalogRevisionId: input.artifact.revision.id, |
| 650 | name: input.source.name, | 659 | name: input.source.name, |
| @@ -663,23 +672,23 @@ const sourceRecordFromCatalogArtifact = (input: { · 12 unmodified lines | |||
| 663 | 672 | ||
| 664 | type RuntimeSourceCatalogStoreShape = { | 673 | type RuntimeSourceCatalogStoreShape = { |
| 665 | loadWorkspaceSourceCatalogs: (input: { | 674 | loadWorkspaceSourceCatalogs: (input: { |
| 666 | workspaceId: WorkspaceId; | 675 | scopeId: ScopeId; |
| 667 | actorAccountId?: AccountId | null; | 676 | actorScopeId?: ScopeId | null; |
| 668 | }) => Effect.Effect<readonly LoadedSourceCatalog[], Error, never>; | 677 | }) => Effect.Effect<readonly LoadedSourceCatalog[], Error, never>; |
| 669 | loadSourceWithCatalog: (input: { | 678 | loadSourceWithCatalog: (input: { |
| 670 | workspaceId: WorkspaceId; | 679 | scopeId: ScopeId; |
| 671 | sourceId: Source["id"]; | 680 | sourceId: Source["id"]; |
| 672 | actorAccountId?: AccountId | null; | 681 | actorScopeId?: ScopeId | null; |
| 673 | }) => Effect.Effect<LoadedSourceCatalog, Error | LocalSourceArtifactMissingError, never>; | 682 | }) => Effect.Effect<LoadedSourceCatalog, Error | LocalSourceArtifactMissingError, never>; |
| 674 | loadWorkspaceSourceCatalogToolIndex: (input: { | 683 | loadWorkspaceSourceCatalogToolIndex: (input: { |
| 675 | workspaceId: WorkspaceId; | 684 | scopeId: ScopeId; |
| 676 | actorAccountId?: AccountId | null; | 685 | actorScopeId?: ScopeId | null; |
| 677 | includeSchemas: boolean; | 686 | includeSchemas: boolean; |
| 678 | }) => Effect.Effect<readonly LoadedSourceCatalogToolIndexEntry[], Error, never>; | 687 | }) => Effect.Effect<readonly LoadedSourceCatalogToolIndexEntry[], Error, never>; |
| 679 | loadWorkspaceSourceCatalogToolByPath: (input: { | 688 | loadWorkspaceSourceCatalogToolByPath: (input: { |
| 680 | workspaceId: WorkspaceId; | 689 | scopeId: ScopeId; |
| 681 | path: string; | 690 | path: string; |
| 682 | actorAccountId?: AccountId | null; | 691 | actorScopeId?: ScopeId | null; |
| 683 | includeSchemas: boolean; | 692 | includeSchemas: boolean; |
| 684 | }) => Effect.Effect<LoadedSourceCatalogToolIndexEntry | null, Error, never>; | 693 | }) => Effect.Effect<LoadedSourceCatalogToolIndexEntry | null, Error, never>; |
| 685 | }; | 694 | }; |
| @@ -691,25 +700,25 @@ export class RuntimeSourceCatalogStoreService extends Context.Tag( · 5 unmodified lines | |||
| 691 | )<RuntimeSourceCatalogStoreService, RuntimeSourceCatalogStoreShape>() {} | 700 | )<RuntimeSourceCatalogStoreService, RuntimeSourceCatalogStoreShape>() {} |
| 692 | 701 | ||
| 693 | type RuntimeSourceCatalogStoreDeps = { | 702 | type RuntimeSourceCatalogStoreDeps = { |
| 694 | runtimeLocalWorkspace: RuntimeLocalWorkspaceState; | 703 | runtimeLocalScope: RuntimeLocalScopeState; |
| 695 | sourceStore: RuntimeSourceStore; | 704 | sourceStore: RuntimeSourceStore; |
| 696 | sourceArtifactStore: SourceArtifactStoreShape; | 705 | sourceArtifactStore: SourceArtifactStoreShape; |
| 697 | }; | 706 | }; |
| 698 | 707 | ||
| 699 | type SourceCatalogRuntimeServices = | 708 | type SourceCatalogRuntimeServices = |
| 700 | | RuntimeLocalWorkspaceService | 709 | | RuntimeLocalScopeService |
| 701 | | RuntimeSourceStoreService | 710 | | RuntimeSourceStoreService |
| 702 | | SourceArtifactStore; | 711 | | SourceArtifactStore; |
| 703 | 712 | ||
| 704 | const ensureRuntimeCatalogWorkspace = ( | 713 | const ensureRuntimeCatalogWorkspace = ( |
| 705 | deps: RuntimeSourceCatalogStoreDeps, | 714 | deps: RuntimeSourceCatalogStoreDeps, |
| 706 | workspaceId: WorkspaceId, | 715 | scopeId: ScopeId, |
| 707 | ) => | 716 | ) => |
| 708 | Effect.gen(function* () { | 717 | Effect.gen(function* () { |
| 709 | if (deps.runtimeLocalWorkspace.installation.workspaceId !== workspaceId) { | 718 | if (deps.runtimeLocalScope.installation.scopeId !== scopeId) { |
| 710 | return yield* Effect.fail( | 719 | return yield* Effect.fail( |
| 711 | runtimeEffectError("catalog/source/runtime", | 720 | runtimeEffectError("catalog/source/runtime", |
| 712 | `Runtime local workspace mismatch: expected ${workspaceId}, got ${deps.runtimeLocalWorkspace.installation.workspaceId}`, | 721 | `Runtime local scope mismatch: expected ${scopeId}, got ${deps.runtimeLocalScope.installation.scopeId}`, |
| 713 | ), | 722 | ), |
| 714 | ); | 723 | ); |
| 715 | } | 724 | } |
| @@ -723,15 +732,15 @@ const buildSnapshotFromArtifact = (input: { · 7 unmodified lines | |||
| 723 | }; | 732 | }; |
| 724 | 733 | ||
| 725 | const loadWorkspaceSourceCatalogsWithDeps = (deps: RuntimeSourceCatalogStoreDeps, input: { | 734 | const loadWorkspaceSourceCatalogsWithDeps = (deps: RuntimeSourceCatalogStoreDeps, input: { |
| 726 | workspaceId: WorkspaceId; | 735 | scopeId: ScopeId; |
| 727 | actorAccountId?: AccountId | null; | 736 | actorScopeId?: ScopeId | null; |
| 728 | }): Effect.Effect<readonly LoadedSourceCatalog[], Error, never> => | 737 | }): Effect.Effect<readonly LoadedSourceCatalog[], Error, never> => |
| 729 | Effect.gen(function* () { | 738 | Effect.gen(function* () { |
| 730 | yield* ensureRuntimeCatalogWorkspace(deps, input.workspaceId); | 739 | yield* ensureRuntimeCatalogWorkspace(deps, input.scopeId); |
| 731 | const sources = yield* deps.sourceStore.loadSourcesInWorkspace( | 740 | const sources = yield* deps.sourceStore.loadSourcesInScope( |
| 732 | input.workspaceId, | 741 | input.scopeId, |
| 733 | { | 742 | { |
| 734 | actorAccountId: input.actorAccountId, | 743 | actorScopeId: input.actorScopeId, |
| 735 | }, | 744 | }, |
| 736 | ); | 745 | ); |
| 737 | 746 | ||
| @@ -773,16 +782,16 @@ const loadWorkspaceSourceCatalogsWithDeps = (deps: RuntimeSourceCatalogStoreDeps · 35 unmodified lines | |||
| 773 | }); | 782 | }); |
| 774 | 783 | ||
| 775 | const loadSourceWithCatalogWithDeps = (deps: RuntimeSourceCatalogStoreDeps, input: { | 784 | const loadSourceWithCatalogWithDeps = (deps: RuntimeSourceCatalogStoreDeps, input: { |
| 776 | workspaceId: WorkspaceId; | 785 | scopeId: ScopeId; |
| 777 | sourceId: Source["id"]; | 786 | sourceId: Source["id"]; |
| 778 | actorAccountId?: AccountId | null; | 787 | actorScopeId?: ScopeId | null; |
| 779 | }): Effect.Effect<LoadedSourceCatalog, Error | LocalSourceArtifactMissingError, never> => | 788 | }): Effect.Effect<LoadedSourceCatalog, Error | LocalSourceArtifactMissingError, never> => |
| 780 | Effect.gen(function* () { | 789 | Effect.gen(function* () { |
| 781 | yield* ensureRuntimeCatalogWorkspace(deps, input.workspaceId); | 790 | yield* ensureRuntimeCatalogWorkspace(deps, input.scopeId); |
| 782 | const source = yield* deps.sourceStore.loadSourceById({ | 791 | const source = yield* deps.sourceStore.loadSourceById({ |
| 783 | workspaceId: input.workspaceId, | 792 | scopeId: input.scopeId, |
| 784 | sourceId: input.sourceId, | 793 | sourceId: input.sourceId, |
| 785 | actorAccountId: input.actorAccountId, | 794 | actorScopeId: input.actorScopeId, |
| 786 | }); | 795 | }); |
| 787 | const artifact = yield* deps.sourceArtifactStore.read({ | 796 | const artifact = yield* deps.sourceArtifactStore.read({ |
| 788 | sourceId: source.id, | 797 | sourceId: source.id, |
| @@ -819,17 +828,17 @@ const loadSourceWithCatalogWithDeps = (deps: RuntimeSourceCatalogStoreDeps, inpu · 30 unmodified lines | |||
| 819 | }); | 828 | }); |
| 820 | 829 | ||
| 821 | export const loadWorkspaceSourceCatalogs = (input: { | 830 | export const loadWorkspaceSourceCatalogs = (input: { |
| 822 | workspaceId: WorkspaceId; | 831 | scopeId: ScopeId; |
| 823 | actorAccountId?: AccountId | null; | 832 | actorScopeId?: ScopeId | null; |
| 824 | }): Effect.Effect<readonly LoadedSourceCatalog[], Error, SourceCatalogRuntimeServices> => | 833 | }): Effect.Effect<readonly LoadedSourceCatalog[], Error, SourceCatalogRuntimeServices> => |
| 825 | Effect.gen(function* () { | 834 | Effect.gen(function* () { |
| 826 | const runtimeLocalWorkspace = yield* RuntimeLocalWorkspaceService; | 835 | const runtimeLocalScope = yield* RuntimeLocalScopeService; |
| 827 | const sourceStore = yield* RuntimeSourceStoreService; | 836 | const sourceStore = yield* RuntimeSourceStoreService; |
| 828 | const sourceArtifactStore = yield* SourceArtifactStore; | 837 | const sourceArtifactStore = yield* SourceArtifactStore; |
| 829 | 838 | ||
| 830 | return yield* loadWorkspaceSourceCatalogsWithDeps( | 839 | return yield* loadWorkspaceSourceCatalogsWithDeps( |
| 831 | { | 840 | { |
| 832 | runtimeLocalWorkspace, | 841 | runtimeLocalScope, |
| 833 | sourceStore, | 842 | sourceStore, |
| 834 | sourceArtifactStore, | 843 | sourceArtifactStore, |
| 835 | }, | 844 | }, |
| @@ -838,22 +847,22 @@ export const loadWorkspaceSourceCatalogs = (input: { · 2 unmodified lines | |||
| 838 | }); | 847 | }); |
| 839 | 848 | ||
| 840 | export const loadSourceWithCatalog = (input: { | 849 | export const loadSourceWithCatalog = (input: { |
| 841 | workspaceId: WorkspaceId; | 850 | scopeId: ScopeId; |
| 842 | sourceId: Source["id"]; | 851 | sourceId: Source["id"]; |
| 843 | actorAccountId?: AccountId | null; | 852 | actorScopeId?: ScopeId | null; |
| 844 | }): Effect.Effect< | 853 | }): Effect.Effect< |
| 845 | LoadedSourceCatalog, | 854 | LoadedSourceCatalog, |
| 846 | Error | LocalSourceArtifactMissingError, | 855 | Error | LocalSourceArtifactMissingError, |
| 847 | SourceCatalogRuntimeServices | 856 | SourceCatalogRuntimeServices |
| 848 | > => | 857 | > => |
| 849 | Effect.gen(function* () { | 858 | Effect.gen(function* () { |
| 850 | const runtimeLocalWorkspace = yield* RuntimeLocalWorkspaceService; | 859 | const runtimeLocalScope = yield* RuntimeLocalScopeService; |
| 851 | const sourceStore = yield* RuntimeSourceStoreService; | 860 | const sourceStore = yield* RuntimeSourceStoreService; |
| 852 | const sourceArtifactStore = yield* SourceArtifactStore; | 861 | const sourceArtifactStore = yield* SourceArtifactStore; |
| 853 | 862 | ||
| 854 | return yield* loadSourceWithCatalogWithDeps( | 863 | return yield* loadSourceWithCatalogWithDeps( |
| 855 | { | 864 | { |
| 856 | runtimeLocalWorkspace, | 865 | runtimeLocalScope, |
| 857 | sourceStore, | 866 | sourceStore, |
| 858 | sourceArtifactStore, | 867 | sourceArtifactStore, |
| 859 | }, | 868 | }, |
| @@ -1096,8 +1105,8 @@ export const expandCatalogToolByPath = (input: { · 236 unmodified lines | |||
| 1096 | ); | 1105 | ); |
| 1097 | 1106 | ||
| 1098 | export const loadWorkspaceSourceCatalogToolIndex = (input: { | 1107 | export const loadWorkspaceSourceCatalogToolIndex = (input: { |
| 1099 | workspaceId: WorkspaceId; | 1108 | scopeId: ScopeId; |
| 1100 | actorAccountId?: AccountId | null; | 1109 | actorScopeId?: ScopeId | null; |
| 1101 | includeSchemas: boolean; | 1110 | includeSchemas: boolean; |
| 1102 | }): Effect.Effect< | 1111 | }): Effect.Effect< |
| 1103 | readonly LoadedSourceCatalogToolIndexEntry[], | 1112 | readonly LoadedSourceCatalogToolIndexEntry[], |
| @@ -1106,8 +1115,8 @@ export const loadWorkspaceSourceCatalogToolIndex = (input: { · 2 unmodified lines | |||
| 1106 | > => | 1115 | > => |
| 1107 | Effect.gen(function* () { | 1116 | Effect.gen(function* () { |
| 1108 | const catalogs = yield* loadWorkspaceSourceCatalogs({ | 1117 | const catalogs = yield* loadWorkspaceSourceCatalogs({ |
| 1109 | workspaceId: input.workspaceId, | 1118 | scopeId: input.scopeId, |
| 1110 | actorAccountId: input.actorAccountId, | 1119 | actorScopeId: input.actorScopeId, |
| 1111 | }); | 1120 | }); |
| 1112 | const tools = yield* expandCatalogTools({ | 1121 | const tools = yield* expandCatalogTools({ |
| 1113 | catalogs, | 1122 | catalogs, |
| @@ -1129,9 +1138,9 @@ export const loadWorkspaceSourceCatalogToolIndex = (input: { · 15 unmodified lines | |||
| 1129 | }); | 1138 | }); |
| 1130 | 1139 | ||
| 1131 | export const loadWorkspaceSourceCatalogToolByPath = (input: { | 1140 | export const loadWorkspaceSourceCatalogToolByPath = (input: { |
| 1132 | workspaceId: WorkspaceId; | 1141 | scopeId: ScopeId; |
| 1133 | path: string; | 1142 | path: string; |
| 1134 | actorAccountId?: AccountId | null; | 1143 | actorScopeId?: ScopeId | null; |
| 1135 | includeSchemas: boolean; | 1144 | includeSchemas: boolean; |
| 1136 | }): Effect.Effect< | 1145 | }): Effect.Effect< |
| 1137 | LoadedSourceCatalogToolIndexEntry | null, | 1146 | LoadedSourceCatalogToolIndexEntry | null, |
| @@ -1140,8 +1149,8 @@ export const loadWorkspaceSourceCatalogToolByPath = (input: { · 2 unmodified lines | |||
| 1140 | > => | 1149 | > => |
| 1141 | Effect.gen(function* () { | 1150 | Effect.gen(function* () { |
| 1142 | const catalogs = yield* loadWorkspaceSourceCatalogs({ | 1151 | const catalogs = yield* loadWorkspaceSourceCatalogs({ |
| 1143 | workspaceId: input.workspaceId, | 1152 | scopeId: input.scopeId, |
| 1144 | actorAccountId: input.actorAccountId, | 1153 | actorScopeId: input.actorScopeId, |
| 1145 | }); | 1154 | }); |
| 1146 | const tool = yield* expandCatalogToolByPath({ | 1155 | const tool = yield* expandCatalogToolByPath({ |
| 1147 | catalogs, | 1156 | catalogs, |
| @@ -1168,12 +1177,12 @@ export const loadWorkspaceSourceCatalogToolByPath = (input: { · 20 unmodified lines | |||
| 1168 | export const RuntimeSourceCatalogStoreLive = Layer.effect( | 1177 | export const RuntimeSourceCatalogStoreLive = Layer.effect( |
| 1169 | RuntimeSourceCatalogStoreService, | 1178 | RuntimeSourceCatalogStoreService, |
| 1170 | Effect.gen(function* () { | 1179 | Effect.gen(function* () { |
| 1171 | const runtimeLocalWorkspace = yield* RuntimeLocalWorkspaceService; | 1180 | const runtimeLocalScope = yield* RuntimeLocalScopeService; |
| 1172 | const sourceStore = yield* RuntimeSourceStoreService; | 1181 | const sourceStore = yield* RuntimeSourceStoreService; |
| 1173 | const sourceArtifactStore = yield* SourceArtifactStore; | 1182 | const sourceArtifactStore = yield* SourceArtifactStore; |
| 1174 | 1183 | ||
| 1175 | const deps: RuntimeSourceCatalogStoreDeps = { | 1184 | const deps: RuntimeSourceCatalogStoreDeps = { |
| 1176 | runtimeLocalWorkspace, | 1185 | runtimeLocalScope, |
| 1177 | sourceStore, | 1186 | sourceStore, |
| 1178 | sourceArtifactStore, | 1187 | sourceArtifactStore, |
| 1179 | }; | 1188 | }; |
| @@ -1185,13 +1194,13 @@ export const RuntimeSourceCatalogStoreLive = Layer.effect( · 5 unmodified lines | |||
| 1185 | loadSourceWithCatalogWithDeps(deps, input), | 1194 | loadSourceWithCatalogWithDeps(deps, input), |
| 1186 | loadWorkspaceSourceCatalogToolIndex: (input) => | 1195 | loadWorkspaceSourceCatalogToolIndex: (input) => |
| 1187 | loadWorkspaceSourceCatalogToolIndex(input).pipe( | 1196 | loadWorkspaceSourceCatalogToolIndex(input).pipe( |
| 1188 | Effect.provideService(RuntimeLocalWorkspaceService, runtimeLocalWorkspace), | 1197 | Effect.provideService(RuntimeLocalScopeService, runtimeLocalScope), |
| 1189 | Effect.provideService(RuntimeSourceStoreService, sourceStore), | 1198 | Effect.provideService(RuntimeSourceStoreService, sourceStore), |
| 1190 | Effect.provideService(SourceArtifactStore, sourceArtifactStore), | 1199 | Effect.provideService(SourceArtifactStore, sourceArtifactStore), |
| 1191 | ), | 1200 | ), |
| 1192 | loadWorkspaceSourceCatalogToolByPath: (input) => | 1201 | loadWorkspaceSourceCatalogToolByPath: (input) => |
| 1193 | loadWorkspaceSourceCatalogToolByPath(input).pipe( | 1202 | loadWorkspaceSourceCatalogToolByPath(input).pipe( |
| 1194 | Effect.provideService(RuntimeLocalWorkspaceService, runtimeLocalWorkspace), | 1203 | Effect.provideService(RuntimeLocalScopeService, runtimeLocalScope), |
| 1195 | Effect.provideService(RuntimeSourceStoreService, sourceStore), | 1204 | Effect.provideService(RuntimeSourceStoreService, sourceStore), |
| 1196 | Effect.provideService(SourceArtifactStore, sourceArtifactStore), | 1205 | Effect.provideService(SourceArtifactStore, sourceArtifactStore), |
| 1197 | ), | 1206 | ), |
| @@ -1,20 +1,34 @@ | |||
| 1 | import { describe, expect, it } from "@effect/vitest"; | 1 | import { |
| 2 | describe, | ||
| 3 | expect, | ||
| 4 | it, | ||
| 5 | } from "@effect/vitest"; | ||
| 2 | 6 | ||
| 3 | import type { Source } from "#schema"; | 7 | import type { |
| 8 | Source, | ||
| 9 | } from "#schema"; | ||
| 4 | 10 | ||
| 5 | import { | 11 | import { |
| 6 | buildGraphqlToolPresentation, | 12 | buildGraphqlToolPresentation, |
| 7 | compileGraphqlToolDefinitions, | 13 | compileGraphqlToolDefinitions, |
| 8 | type GraphqlToolManifest, | 14 | type GraphqlToolManifest, |
| 9 | } from "@executor/source-graphql"; | 15 | } from "@executor/source-graphql"; |
| 10 | import { createGoogleDiscoveryCatalogSnapshot } from "@executor/source-google-discovery"; | 16 | import { |
| 11 | import { createGraphqlCatalogSnapshot } from "@executor/source-graphql"; | 17 | createGoogleDiscoveryCatalogSnapshot, |
| 12 | import { createMcpCatalogSnapshot } from "@executor/source-mcp"; | 18 | } from "@executor/source-google-discovery"; |
| 13 | import { createOpenApiCatalogSnapshot } from "@executor/source-openapi"; | 19 | import { |
| 20 | createGraphqlCatalogSnapshot, | ||
| 21 | } from "@executor/source-graphql"; | ||
| 22 | import { | ||
| 23 | createMcpCatalogSnapshot, | ||
| 24 | } from "@executor/source-mcp"; | ||
| 25 | import { | ||
| 26 | createOpenApiCatalogSnapshot, | ||
| 27 | } from "@executor/source-openapi"; | ||
| 14 | 28 | ||
| 15 | const baseSource: Source = { | 29 | const baseSource: Source = { |
| 16 | id: "src_calendar" as Source["id"], | 30 | id: "src_calendar" as Source["id"], |
| 17 | workspaceId: "ws_test" as Source["workspaceId"], | 31 | scopeId: "ws_test" as Source["scopeId"], |
| 18 | name: "Calendar", | 32 | name: "Calendar", |
| 19 | kind: "openapi", | 33 | kind: "openapi", |
| 20 | endpoint: "https://api.example.test", | 34 | endpoint: "https://api.example.test", |
| @@ -1,26 +1,28 @@ | |||
| 1 | import type { | 1 | import type { |
| 2 | AccountId, | 2 | ScopeId, |
| 3 | Source, | 3 | Source, |
| 4 | SourceStatus, | 4 | SourceStatus, |
| 5 | } from "#schema"; | 5 | } from "#schema"; |
| 6 | import type { McpToolManifest } from "@executor/source-mcp"; | 6 | import type { |
| 7 | McpToolManifest, | ||
| 8 | } from "@executor/source-mcp"; | ||
| 7 | import * as Context from "effect/Context"; | 9 | import * as Context from "effect/Context"; |
| 8 | import * as Effect from "effect/Effect"; | 10 | import * as Effect from "effect/Effect"; |
| 9 | import * as Layer from "effect/Layer"; | 11 | import * as Layer from "effect/Layer"; |
| 10 | 12 | ||
| 11 | import { | 13 | import { |
| 12 | RuntimeLocalWorkspaceService, | 14 | RuntimeLocalScopeService, |
| 13 | type RuntimeLocalWorkspaceState, | 15 | type RuntimeLocalScopeState, |
| 14 | } from "../../workspace/runtime-context"; | 16 | } from "../../scope/runtime-context"; |
| 15 | import { | 17 | import { |
| 16 | SourceArtifactStore, | 18 | SourceArtifactStore, |
| 17 | type SourceArtifactStoreShape, | 19 | type SourceArtifactStoreShape, |
| 18 | WorkspaceStateStore, | 20 | ScopeStateStore, |
| 19 | type WorkspaceStateStoreShape, | 21 | type ScopeStateStoreShape, |
| 20 | } from "../../workspace/storage"; | 22 | } from "../../scope/storage"; |
| 21 | import { | 23 | import { |
| 22 | type LocalWorkspaceState, | 24 | type LocalScopeState, |
| 23 | } from "../../workspace-state"; | 25 | } from "../../scope-state"; |
| 24 | import { | 26 | import { |
| 25 | RuntimeSourceAuthMaterialService, | 27 | RuntimeSourceAuthMaterialService, |
| 26 | } from "../../auth/source-auth-material"; | 28 | } from "../../auth/source-auth-material"; |
| @@ -30,13 +32,19 @@ import { · 3 unmodified lines | |||
| 30 | import { | 32 | import { |
| 31 | catalogSyncResultFromMcpManifest, | 33 | catalogSyncResultFromMcpManifest, |
| 32 | } from "@executor/source-mcp"; | 34 | } from "@executor/source-mcp"; |
| 33 | import { SecretMaterialResolverService } from "../../workspace/secret-material-providers"; | 35 | import { |
| 34 | import { snapshotFromSourceCatalogSyncResult } from "@executor/source-core"; | 36 | SecretMaterialResolverService, |
| 37 | } from "../../scope/secret-material-providers"; | ||
| 38 | import { | ||
| 39 | snapshotFromSourceCatalogSyncResult, | ||
| 40 | } from "@executor/source-core"; | ||
| 35 | import { | 41 | import { |
| 36 | SourceTypeDeclarationsRefresherService, | 42 | SourceTypeDeclarationsRefresherService, |
| 37 | type SourceTypeDeclarationsRefresherShape, | 43 | type SourceTypeDeclarationsRefresherShape, |
| 38 | } from "./type-declarations"; | 44 | } from "./type-declarations"; |
| 39 | import { runtimeEffectError } from "../../effect-errors"; | 45 | import { |
| 46 | runtimeEffectError, | ||
| 47 | } from "../../effect-errors"; | ||
| 40 | 48 | ||
| 41 | const shouldIndexSource = (source: Source): boolean => | 49 | const shouldIndexSource = (source: Source): boolean => |
| 42 | source.enabled | 50 | source.enabled |
| @@ -44,8 +52,8 @@ const shouldIndexSource = (source: Source): boolean => · 1 unmodified line | |||
| 44 | && getSourceAdapterForSource(source).catalogKind !== "internal"; | 52 | && getSourceAdapterForSource(source).catalogKind !== "internal"; |
| 45 | 53 | ||
| 46 | type RuntimeSourceCatalogSyncDeps = { | 54 | type RuntimeSourceCatalogSyncDeps = { |
| 47 | runtimeLocalWorkspace: RuntimeLocalWorkspaceState; | 55 | runtimeLocalScope: RuntimeLocalScopeState; |
| 48 | workspaceStateStore: WorkspaceStateStoreShape; | 56 | scopeStateStore: ScopeStateStoreShape; |
| 49 | sourceArtifactStore: SourceArtifactStoreShape; | 57 | sourceArtifactStore: SourceArtifactStoreShape; |
| 50 | sourceTypeDeclarationsRefresher: SourceTypeDeclarationsRefresherShape; | 58 | sourceTypeDeclarationsRefresher: SourceTypeDeclarationsRefresherShape; |
| 51 | resolveSecretMaterial: Effect.Effect.Success<typeof SecretMaterialResolverService>; | 59 | resolveSecretMaterial: Effect.Effect.Success<typeof SecretMaterialResolverService>; |
| @@ -53,8 +61,8 @@ type RuntimeSourceCatalogSyncDeps = { · 1 unmodified line | |||
| 53 | }; | 61 | }; |
| 54 | 62 | ||
| 55 | type SourceCatalogSyncServices = | 63 | type SourceCatalogSyncServices = |
| 56 | | RuntimeLocalWorkspaceService | 64 | | RuntimeLocalScopeService |
| 57 | | WorkspaceStateStore | 65 | | ScopeStateStore |
| 58 | | SourceArtifactStore | 66 | | SourceArtifactStore |
| 59 | | SourceTypeDeclarationsRefresherService | 67 | | SourceTypeDeclarationsRefresherService |
| 60 | | RuntimeSourceAuthMaterialService | 68 | | RuntimeSourceAuthMaterialService |
| @@ -63,7 +71,7 @@ type SourceCatalogSyncServices = · 2 unmodified lines | |||
| 63 | export type RuntimeSourceCatalogSyncShape = { | 71 | export type RuntimeSourceCatalogSyncShape = { |
| 64 | sync: (input: { | 72 | sync: (input: { |
| 65 | source: Source; | 73 | source: Source; |
| 66 | actorAccountId?: AccountId | null; | 74 | actorScopeId?: ScopeId | null; |
| 67 | }) => Effect.Effect<void, Error, never>; | 75 | }) => Effect.Effect<void, Error, never>; |
| 68 | persistMcpCatalogSnapshotFromManifest: (input: { | 76 | persistMcpCatalogSnapshotFromManifest: (input: { |
| 69 | source: Source; | 77 | source: Source; |
| @@ -77,13 +85,13 @@ export class RuntimeSourceCatalogSyncService extends Context.Tag( · 7 unmodified lines | |||
| 77 | 85 | ||
| 78 | const ensureRuntimeCatalogSyncWorkspace = ( | 86 | const ensureRuntimeCatalogSyncWorkspace = ( |
| 79 | deps: RuntimeSourceCatalogSyncDeps, | 87 | deps: RuntimeSourceCatalogSyncDeps, |
| 80 | workspaceId: Source["workspaceId"], | 88 | scopeId: Source["scopeId"], |
| 81 | ) => | 89 | ) => |
| 82 | Effect.gen(function* () { | 90 | Effect.gen(function* () { |
| 83 | if (deps.runtimeLocalWorkspace.installation.workspaceId !== workspaceId) { | 91 | if (deps.runtimeLocalScope.installation.scopeId !== scopeId) { |
| 84 | return yield* Effect.fail( | 92 | return yield* Effect.fail( |
| 85 | runtimeEffectError("catalog/source/sync", | 93 | runtimeEffectError("catalog/source/sync", |
| 86 | `Runtime local workspace mismatch: expected ${workspaceId}, got ${deps.runtimeLocalWorkspace.installation.workspaceId}`, | 94 | `Runtime local scope mismatch: expected ${scopeId}, got ${deps.runtimeLocalScope.installation.scopeId}`, |
| 87 | ), | 95 | ), |
| 88 | ); | 96 | ); |
| 89 | } | 97 | } |
| @@ -93,16 +101,16 @@ const syncSourceCatalogWithDeps = ( · 3 unmodified lines | |||
| 93 | deps: RuntimeSourceCatalogSyncDeps, | 101 | deps: RuntimeSourceCatalogSyncDeps, |
| 94 | input: { | 102 | input: { |
| 95 | source: Source; | 103 | source: Source; |
| 96 | actorAccountId?: AccountId | null; | 104 | actorScopeId?: ScopeId | null; |
| 97 | }, | 105 | }, |
| 98 | ): Effect.Effect<void, Error, never> => | 106 | ): Effect.Effect<void, Error, never> => |
| 99 | Effect.gen(function* () { | 107 | Effect.gen(function* () { |
| 100 | yield* ensureRuntimeCatalogSyncWorkspace(deps, input.source.workspaceId); | 108 | yield* ensureRuntimeCatalogSyncWorkspace(deps, input.source.scopeId); |
| 101 | 109 | ||
| 102 | if (!shouldIndexSource(input.source)) { | 110 | if (!shouldIndexSource(input.source)) { |
| 103 | const state = yield* deps.workspaceStateStore.load(); | 111 | const state = yield* deps.scopeStateStore.load(); |
| 104 | const existingSourceState = state.sources[input.source.id]; | 112 | const existingSourceState = state.sources[input.source.id]; |
| 105 | const nextState: LocalWorkspaceState = { | 113 | const nextState: LocalScopeState = { |
| 106 | ...state, | 114 | ...state, |
| 107 | sources: { | 115 | sources: { |
| 108 | ...state.sources, | 116 | ...state.sources, |
| @@ -115,7 +123,7 @@ const syncSourceCatalogWithDeps = ( · 6 unmodified lines | |||
| 115 | }, | 123 | }, |
| 116 | }, | 124 | }, |
| 117 | }; | 125 | }; |
| 118 | yield* deps.workspaceStateStore.write({ | 126 | yield* deps.scopeStateStore.write({ |
| 119 | state: nextState, | 127 | state: nextState, |
| 120 | }); | 128 | }); |
| 121 | yield* deps.sourceTypeDeclarationsRefresher.refreshSourceInBackground({ | 129 | yield* deps.sourceTypeDeclarationsRefresher.refreshSourceInBackground({ |
| @@ -133,7 +141,7 @@ const syncSourceCatalogWithDeps = ( · 11 unmodified lines | |||
| 133 | deps.sourceAuthMaterialService.resolve({ | 141 | deps.sourceAuthMaterialService.resolve({ |
| 134 | source: input.source, | 142 | source: input.source, |
| 135 | slot, | 143 | slot, |
| 136 | actorAccountId: input.actorAccountId, | 144 | actorScopeId: input.actorScopeId, |
| 137 | }), | 145 | }), |
| 138 | }); | 146 | }); |
| 139 | const snapshot = snapshotFromSourceCatalogSyncResult(syncResult); | 147 | const snapshot = snapshotFromSourceCatalogSyncResult(syncResult); |
| @@ -145,9 +153,9 @@ const syncSourceCatalogWithDeps = ( · 5 unmodified lines | |||
| 145 | }), | 153 | }), |
| 146 | }); | 154 | }); |
| 147 | 155 | ||
| 148 | const state = yield* deps.workspaceStateStore.load(); | 156 | const state = yield* deps.scopeStateStore.load(); |
| 149 | const existingSourceState = state.sources[input.source.id]; | 157 | const existingSourceState = state.sources[input.source.id]; |
| 150 | const nextState: LocalWorkspaceState = { | 158 | const nextState: LocalScopeState = { |
| 151 | ...state, | 159 | ...state, |
| 152 | sources: { | 160 | sources: { |
| 153 | ...state.sources, | 161 | ...state.sources, |
| @@ -160,7 +168,7 @@ const syncSourceCatalogWithDeps = ( · 6 unmodified lines | |||
| 160 | }, | 168 | }, |
| 161 | }, | 169 | }, |
| 162 | }; | 170 | }; |
| 163 | yield* deps.workspaceStateStore.write({ | 171 | yield* deps.scopeStateStore.write({ |
| 164 | state: nextState, | 172 | state: nextState, |
| 165 | }); | 173 | }); |
| 166 | 174 | ||
| @@ -187,7 +195,7 @@ const persistMcpCatalogSnapshotFromManifestWithDeps = ( · 20 unmodified lines | |||
| 187 | }, | 195 | }, |
| 188 | ): Effect.Effect<void, Error, never> => | 196 | ): Effect.Effect<void, Error, never> => |
| 189 | Effect.gen(function* () { | 197 | Effect.gen(function* () { |
| 190 | yield* ensureRuntimeCatalogSyncWorkspace(deps, input.source.workspaceId); | 198 | yield* ensureRuntimeCatalogSyncWorkspace(deps, input.source.scopeId); |
| 191 | const syncResult = catalogSyncResultFromMcpManifest({ | 199 | const syncResult = catalogSyncResultFromMcpManifest({ |
| 192 | source: input.source, | 200 | source: input.source, |
| 193 | endpoint: input.source.endpoint, | 201 | endpoint: input.source.endpoint, |
| @@ -211,11 +219,11 @@ const persistMcpCatalogSnapshotFromManifestWithDeps = ( · 17 unmodified lines | |||
| 211 | 219 | ||
| 212 | export const syncSourceCatalog = (input: { | 220 | export const syncSourceCatalog = (input: { |
| 213 | source: Source; | 221 | source: Source; |
| 214 | actorAccountId?: AccountId | null; | 222 | actorScopeId?: ScopeId | null; |
| 215 | }): Effect.Effect<void, Error, SourceCatalogSyncServices> => | 223 | }): Effect.Effect<void, Error, SourceCatalogSyncServices> => |
| 216 | Effect.gen(function* () { | 224 | Effect.gen(function* () { |
| 217 | const runtimeLocalWorkspace = yield* RuntimeLocalWorkspaceService; | 225 | const runtimeLocalScope = yield* RuntimeLocalScopeService; |
| 218 | const workspaceStateStore = yield* WorkspaceStateStore; | 226 | const scopeStateStore = yield* ScopeStateStore; |
| 219 | const sourceArtifactStore = yield* SourceArtifactStore; | 227 | const sourceArtifactStore = yield* SourceArtifactStore; |
| 220 | const sourceTypeDeclarationsRefresher = | 228 | const sourceTypeDeclarationsRefresher = |
| 221 | yield* SourceTypeDeclarationsRefresherService; | 229 | yield* SourceTypeDeclarationsRefresherService; |
| @@ -224,8 +232,8 @@ export const syncSourceCatalog = (input: { · 2 unmodified lines | |||
| 224 | 232 | ||
| 225 | return yield* syncSourceCatalogWithDeps( | 233 | return yield* syncSourceCatalogWithDeps( |
| 226 | { | 234 | { |
| 227 | runtimeLocalWorkspace, | 235 | runtimeLocalScope, |
| 228 | workspaceStateStore, | 236 | scopeStateStore, |
| 229 | sourceArtifactStore, | 237 | sourceArtifactStore, |
| 230 | sourceTypeDeclarationsRefresher, | 238 | sourceTypeDeclarationsRefresher, |
| 231 | resolveSecretMaterial, | 239 | resolveSecretMaterial, |
| @@ -233,7 +241,7 @@ export const syncSourceCatalog = (input: { · 1 unmodified line | |||
| 233 | }, | 241 | }, |
| 234 | { | 242 | { |
| 235 | source: input.source, | 243 | source: input.source, |
| 236 | actorAccountId: input.actorAccountId, | 244 | actorScopeId: input.actorScopeId, |
| 237 | }, | 245 | }, |
| 238 | ); | 246 | ); |
| 239 | }); | 247 | }); |
| @@ -243,8 +251,8 @@ export const persistMcpCatalogSnapshotFromManifest = (input: { · 3 unmodified lines | |||
| 243 | manifest: McpToolManifest; | 251 | manifest: McpToolManifest; |
| 244 | }): Effect.Effect<void, Error, SourceCatalogSyncServices> => | 252 | }): Effect.Effect<void, Error, SourceCatalogSyncServices> => |
| 245 | Effect.gen(function* () { | 253 | Effect.gen(function* () { |
| 246 | const runtimeLocalWorkspace = yield* RuntimeLocalWorkspaceService; | 254 | const runtimeLocalScope = yield* RuntimeLocalScopeService; |
| 247 | const workspaceStateStore = yield* WorkspaceStateStore; | 255 | const scopeStateStore = yield* ScopeStateStore; |
| 248 | const sourceArtifactStore = yield* SourceArtifactStore; | 256 | const sourceArtifactStore = yield* SourceArtifactStore; |
| 249 | const sourceTypeDeclarationsRefresher = | 257 | const sourceTypeDeclarationsRefresher = |
| 250 | yield* SourceTypeDeclarationsRefresherService; | 258 | yield* SourceTypeDeclarationsRefresherService; |
| @@ -253,8 +261,8 @@ export const persistMcpCatalogSnapshotFromManifest = (input: { · 2 unmodified lines | |||
| 253 | 261 | ||
| 254 | return yield* persistMcpCatalogSnapshotFromManifestWithDeps( | 262 | return yield* persistMcpCatalogSnapshotFromManifestWithDeps( |
| 255 | { | 263 | { |
| 256 | runtimeLocalWorkspace, | 264 | runtimeLocalScope, |
| 257 | workspaceStateStore, | 265 | scopeStateStore, |
| 258 | sourceArtifactStore, | 266 | sourceArtifactStore, |
| 259 | sourceTypeDeclarationsRefresher, | 267 | sourceTypeDeclarationsRefresher, |
| 260 | resolveSecretMaterial, | 268 | resolveSecretMaterial, |
| @@ -267,8 +275,8 @@ export const persistMcpCatalogSnapshotFromManifest = (input: { · 6 unmodified lines | |||
| 267 | export const RuntimeSourceCatalogSyncLive = Layer.effect( | 275 | export const RuntimeSourceCatalogSyncLive = Layer.effect( |
| 268 | RuntimeSourceCatalogSyncService, | 276 | RuntimeSourceCatalogSyncService, |
| 269 | Effect.gen(function* () { | 277 | Effect.gen(function* () { |
| 270 | const runtimeLocalWorkspace = yield* RuntimeLocalWorkspaceService; | 278 | const runtimeLocalScope = yield* RuntimeLocalScopeService; |
| 271 | const workspaceStateStore = yield* WorkspaceStateStore; | 279 | const scopeStateStore = yield* ScopeStateStore; |
| 272 | const sourceArtifactStore = yield* SourceArtifactStore; | 280 | const sourceArtifactStore = yield* SourceArtifactStore; |
| 273 | const sourceTypeDeclarationsRefresher = | 281 | const sourceTypeDeclarationsRefresher = |
| 274 | yield* SourceTypeDeclarationsRefresherService; | 282 | yield* SourceTypeDeclarationsRefresherService; |
| @@ -276,8 +284,8 @@ export const RuntimeSourceCatalogSyncLive = Layer.effect( · 1 unmodified line | |||
| 276 | const sourceAuthMaterialService = yield* RuntimeSourceAuthMaterialService; | 284 | const sourceAuthMaterialService = yield* RuntimeSourceAuthMaterialService; |
| 277 | 285 | ||
| 278 | const deps: RuntimeSourceCatalogSyncDeps = { | 286 | const deps: RuntimeSourceCatalogSyncDeps = { |
| 279 | runtimeLocalWorkspace, | 287 | runtimeLocalScope, |
| 280 | workspaceStateStore, | 288 | scopeStateStore, |
| 281 | sourceArtifactStore, | 289 | sourceArtifactStore, |
| 282 | sourceTypeDeclarationsRefresher, | 290 | sourceTypeDeclarationsRefresher, |
| 283 | resolveSecretMaterial, | 291 | resolveSecretMaterial, |
| @@ -1,5 +1,9 @@ | |||
| 1 | import type { Source } from "#schema"; | 1 | import type { |
| 2 | import type { CatalogSnapshotV1 } from "@executor/ir/model"; | 2 | Source, |
| 3 | } from "#schema"; | ||
| 4 | import type { | ||
| 5 | CatalogSnapshotV1, | ||
| 6 | } from "@executor/ir/model"; | ||
| 3 | import * as Context from "effect/Context"; | 7 | import * as Context from "effect/Context"; |
| 4 | import * as Effect from "effect/Effect"; | 8 | import * as Effect from "effect/Effect"; |
| 5 | 9 | ||
| @@ -1,16 +1,36 @@ | |||
| 1 | import { tmpdir } from "node:os"; | 1 | import { |
| 2 | import { join } from "node:path"; | 2 | tmpdir, |
| 3 | import { FileSystem } from "@effect/platform"; | 3 | } from "node:os"; |
| 4 | import { NodeFileSystem } from "@effect/platform-node"; | 4 | import { |
| 5 | import { describe, expect, it } from "@effect/vitest"; | 5 | join, |
| 6 | } from "node:path"; | ||
| 7 | import { | ||
| 8 | FileSystem, | ||
| 9 | } from "@effect/platform"; | ||
| 10 | import { | ||
| 11 | NodeFileSystem, | ||
| 12 | } from "@effect/platform-node"; | ||
| 13 | import { | ||
| 14 | describe, | ||
| 15 | expect, | ||
| 16 | it, | ||
| 17 | } from "@effect/vitest"; | ||
| 6 | import * as Effect from "effect/Effect"; | 18 | import * as Effect from "effect/Effect"; |
| 7 | import * as Schema from "effect/Schema"; | 19 | import * as Schema from "effect/Schema"; |
| 8 | 20 | ||
| 9 | import { makeToolInvokerFromTools } from "@executor/codemode-core"; | 21 | import { |
| 10 | import { makeDenoSubprocessExecutor } from "@executor/runtime-deno-subprocess"; | 22 | makeToolInvokerFromTools, |
| 23 | } from "@executor/codemode-core"; | ||
| 24 | import { | ||
| 25 | makeDenoSubprocessExecutor, | ||
| 26 | } from "@executor/runtime-deno-subprocess"; | ||
| 11 | 27 | ||
| 12 | import { createLocalExecutorRuntime as createExecutorRuntime } from "../../../../sdk-file/src/index"; | 28 | import { |
| 13 | import { withExecutorApiClient } from "./test-http-client"; | 29 | createLocalExecutorRuntime as createExecutorRuntime, |
| 30 | } from "../../../../sdk-file/src/index"; | ||
| 31 | import { | ||
| 32 | withExecutorApiClient, | ||
| 33 | } from "./test-http-client"; | ||
| 14 | 34 | ||
| 15 | const makeExecutionResolver = () => { | 35 | const makeExecutionResolver = () => { |
| 16 | const toolInvoker = makeToolInvokerFromTools({ | 36 | const toolInvoker = makeToolInvokerFromTools({ |
| @@ -41,22 +61,22 @@ const makeExecutionResolver = () => { · 24 unmodified lines | |||
| 41 | const makeRuntime = Effect.acquireRelease( | 61 | const makeRuntime = Effect.acquireRelease( |
| 42 | Effect.gen(function* () { | 62 | Effect.gen(function* () { |
| 43 | const fs = yield* FileSystem.FileSystem; | 63 | const fs = yield* FileSystem.FileSystem; |
| 44 | const workspaceRoot = yield* fs.makeTempDirectory({ | 64 | const scopeRoot = yield* fs.makeTempDirectory({ |
| 45 | directory: tmpdir(), | 65 | directory: tmpdir(), |
| 46 | prefix: "executor-execution-http-", | 66 | prefix: "executor-execution-http-", |
| 47 | }); | 67 | }); |
| 48 | 68 | ||
| 49 | return { | 69 | return { |
| 50 | workspaceRoot, | 70 | scopeRoot, |
| 51 | homeConfigPath: join(workspaceRoot, ".executor-home.jsonc"), | 71 | homeConfigPath: join(scopeRoot, ".executor-home.jsonc"), |
| 52 | homeStateDirectory: join(workspaceRoot, ".executor-home-state"), | 72 | homeStateDirectory: join(scopeRoot, ".executor-home-state"), |
| 53 | }; | 73 | }; |
| 54 | }).pipe( | 74 | }).pipe( |
| 55 | Effect.provide(NodeFileSystem.layer), | 75 | Effect.provide(NodeFileSystem.layer), |
| 56 | Effect.flatMap(({ workspaceRoot, homeConfigPath, homeStateDirectory }) => | 76 | Effect.flatMap(({ scopeRoot, homeConfigPath, homeStateDirectory }) => |
| 57 | createExecutorRuntime({ | 77 | createExecutorRuntime({ |
| 58 | localDataDir: ":memory:", | 78 | localDataDir: ":memory:", |
| 59 | workspaceRoot, | 79 | workspaceRoot: scopeRoot, |
| 60 | homeConfigPath, | 80 | homeConfigPath, |
| 61 | homeStateDirectory, | 81 | homeStateDirectory, |
| 62 | executionResolver: makeExecutionResolver(), | 82 | executionResolver: makeExecutionResolver(), |
| @@ -75,12 +95,12 @@ describe("execution-http", () => { · 12 unmodified lines | |||
| 75 | const createExecution = yield* withExecutorApiClient( | 95 | const createExecution = yield* withExecutorApiClient( |
| 76 | { | 96 | { |
| 77 | runtime, | 97 | runtime, |
| 78 | accountId: installation.accountId, | 98 | actorScopeId: installation.actorScopeId, |
| 79 | }, | 99 | }, |
| 80 | (client) => | 100 | (client) => |
| 81 | client.executions.create({ | 101 | client.executions.create({ |
| 82 | path: { | 102 | path: { |
| 83 | workspaceId: installation.workspaceId, | 103 | scopeId: installation.scopeId, |
| 84 | }, | 104 | }, |
| 85 | payload: { | 105 | payload: { |
| 86 | code: "return await tools.math.add({ a: 20, b: 22 });", | 106 | code: "return await tools.math.add({ a: 20, b: 22 });", |
| @@ -95,12 +115,12 @@ describe("execution-http", () => { · 8 unmodified lines | |||
| 95 | const getExecution = yield* withExecutorApiClient( | 115 | const getExecution = yield* withExecutorApiClient( |
| 96 | { | 116 | { |
| 97 | runtime, | 117 | runtime, |
| 98 | accountId: installation.accountId, | 118 | actorScopeId: installation.actorScopeId, |
| 99 | }, | 119 | }, |
| 100 | (client) => | 120 | (client) => |
| 101 | client.executions.get({ | 121 | client.executions.get({ |
| 102 | path: { | 122 | path: { |
| 103 | workspaceId: installation.workspaceId, | 123 | scopeId: installation.scopeId, |
| 104 | executionId: createExecution.execution.id, | 124 | executionId: createExecution.execution.id, |
| 105 | }, | 125 | }, |
| 106 | }), | 126 | }), |
| @@ -1,11 +1,24 @@ | |||
| 1 | import type { AccountId, Source } from "#schema"; | 1 | import type { |
| 2 | import type { OnElicitation } from "@executor/codemode-core"; | 2 | ScopeId, |
| 3 | Source, | ||
| 4 | } from "#schema"; | ||
| 5 | import type { | ||
| 6 | OnElicitation, | ||
| 7 | } from "@executor/codemode-core"; | ||
| 3 | import * as Effect from "effect/Effect"; | 8 | import * as Effect from "effect/Effect"; |
| 4 | 9 | ||
| 5 | import type { LoadedSourceCatalogToolIndexEntry } from "../catalog/source/runtime"; | 10 | import type { |
| 6 | import type { ResolvedSourceAuthMaterial } from "../auth/source-auth-material"; | 11 | LoadedSourceCatalogToolIndexEntry, |
| 7 | import { getSourceAdapter } from "../sources/source-adapters"; | 12 | } from "../catalog/source/runtime"; |
| 8 | import { runtimeEffectError } from "../effect-errors"; | 13 | import type { |
| 14 | ResolvedSourceAuthMaterial, | ||
| 15 | } from "../auth/source-auth-material"; | ||
| 16 | import { | ||
| 17 | getSourceAdapter, | ||
| 18 | } from "../sources/source-adapters"; | ||
| 19 | import { | ||
| 20 | runtimeEffectError, | ||
| 21 | } from "../effect-errors"; | ||
| 9 | 22 | ||
| 10 | export const invocationDescriptorFromTool = (input: { | 23 | export const invocationDescriptorFromTool = (input: { |
| 11 | tool: LoadedSourceCatalogToolIndexEntry; | 24 | tool: LoadedSourceCatalogToolIndexEntry; |
| @@ -39,8 +52,8 @@ export const invocationDescriptorFromTool = (input: { · 27 unmodified lines | |||
| 39 | }); | 52 | }); |
| 40 | 53 | ||
| 41 | export const invokeIrTool = (input: { | 54 | export const invokeIrTool = (input: { |
| 42 | workspaceId: Source["workspaceId"]; | 55 | scopeId: Source["scopeId"]; |
| 43 | accountId: AccountId; | 56 | actorScopeId: ScopeId; |
| 44 | tool: LoadedSourceCatalogToolIndexEntry; | 57 | tool: LoadedSourceCatalogToolIndexEntry; |
| 45 | auth: ResolvedSourceAuthMaterial; | 58 | auth: ResolvedSourceAuthMaterial; |
| 46 | args: unknown; | 59 | args: unknown; |
| @@ -1,6 +1,12 @@ | |||
| 1 | import { describe, expect, it } from "@effect/vitest"; | 1 | import { |
| 2 | describe, | ||
| 3 | expect, | ||
| 4 | it, | ||
| 5 | } from "@effect/vitest"; | ||
| 2 | 6 | ||
| 3 | import { sanitizePersistedElicitationResponse } from "./live"; | 7 | import { |
| 8 | sanitizePersistedElicitationResponse, | ||
| 9 | } from "./live"; | ||
| 4 | 10 | ||
| 5 | describe("live-execution", () => { | 11 | describe("live-execution", () => { |
| 6 | it("redacts secret refs from persisted interaction responses", () => { | 12 | it("redacts secret refs from persisted interaction responses", () => { |
| @@ -2,7 +2,9 @@ import type { · 1 unmodified line | |||
| 2 | ElicitationResponse, | 2 | ElicitationResponse, |
| 3 | OnElicitation, | 3 | OnElicitation, |
| 4 | } from "@executor/codemode-core"; | 4 | } from "@executor/codemode-core"; |
| 5 | import { clearMcpConnectionPoolRun } from "@executor/source-mcp"; | 5 | import { |
| 6 | clearMcpConnectionPoolRun, | ||
| 7 | } from "@executor/source-mcp"; | ||
| 6 | import { | 8 | import { |
| 7 | ExecutionInteractionIdSchema, | 9 | ExecutionInteractionIdSchema, |
| 8 | type Execution, | 10 | type Execution, |
| @@ -13,7 +15,9 @@ import * as Deferred from "effect/Deferred"; · 4 unmodified lines | |||
| 13 | import * as Effect from "effect/Effect"; | 15 | import * as Effect from "effect/Effect"; |
| 14 | import * as Layer from "effect/Layer"; | 16 | import * as Layer from "effect/Layer"; |
| 15 | 17 | ||
| 16 | import type { ExecutorStateStoreShape } from "../executor-state-store"; | 18 | import type { |
| 19 | ExecutorStateStoreShape, | ||
| 20 | } from "../executor-state-store"; | ||
| 17 | 21 | ||
| 18 | type VisibleExecutionState = | 22 | type VisibleExecutionState = |
| 19 | | "running" | 23 | | "running" |
| @@ -1,29 +1,67 @@ | |||
| 1 | import { randomUUID } from "node:crypto"; | 1 | import { |
| 2 | 2 | randomUUID, | |
| 3 | import { createMcpExpressApp } from "@modelcontextprotocol/sdk/server/express.js"; | 3 | } from "node:crypto"; |
| 4 | import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; | 4 | |
| 5 | import { Client } from "@modelcontextprotocol/sdk/client/index.js"; | 5 | import { |
| 6 | import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js"; | 6 | createMcpExpressApp, |
| 7 | import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js"; | 7 | } from "@modelcontextprotocol/sdk/server/express.js"; |
| 8 | import { tmpdir } from "node:os"; | 8 | import { |
| 9 | import { join } from "node:path"; | 9 | McpServer, |
| 10 | import { FileSystem } from "@effect/platform"; | 10 | } from "@modelcontextprotocol/sdk/server/mcp.js"; |
| 11 | import { NodeFileSystem } from "@effect/platform-node"; | 11 | import { |
| 12 | import { describe, expect, it } from "@effect/vitest"; | 12 | Client, |
| 13 | import { assertTrue } from "@effect/vitest/utils"; | 13 | } from "@modelcontextprotocol/sdk/client/index.js"; |
| 14 | import { | ||
| 15 | StreamableHTTPClientTransport, | ||
| 16 | } from "@modelcontextprotocol/sdk/client/streamableHttp.js"; | ||
| 17 | import { | ||
| 18 | StreamableHTTPServerTransport, | ||
| 19 | } from "@modelcontextprotocol/sdk/server/streamableHttp.js"; | ||
| 20 | import { | ||
| 21 | tmpdir, | ||
| 22 | } from "node:os"; | ||
| 23 | import { | ||
| 24 | join, | ||
| 25 | } from "node:path"; | ||
| 26 | import { | ||
| 27 | FileSystem, | ||
| 28 | } from "@effect/platform"; | ||
| 29 | import { | ||
| 30 | NodeFileSystem, | ||
| 31 | } from "@effect/platform-node"; | ||
| 32 | import { | ||
| 33 | describe, | ||
| 34 | expect, | ||
| 35 | it, | ||
| 36 | } from "@effect/vitest"; | ||
| 37 | import { | ||
| 38 | assertTrue, | ||
| 39 | } from "@effect/vitest/utils"; | ||
| 14 | import * as Effect from "effect/Effect"; | 40 | import * as Effect from "effect/Effect"; |
| 15 | import * as Option from "effect/Option"; | 41 | import * as Option from "effect/Option"; |
| 16 | import { z } from "zod/v4"; | 42 | import { |
| 43 | z, | ||
| 44 | } from "zod/v4"; | ||
| 17 | 45 | ||
| 18 | import { makeToolInvokerFromTools } from "@executor/codemode-core"; | 46 | import { |
| 19 | import { discoverMcpToolsFromConnector } from "@executor/source-mcp"; | 47 | makeToolInvokerFromTools, |
| 20 | import { makeDenoSubprocessExecutor } from "@executor/runtime-deno-subprocess"; | 48 | } from "@executor/codemode-core"; |
| 49 | import { | ||
| 50 | discoverMcpToolsFromConnector, | ||
| 51 | } from "@executor/source-mcp"; | ||
| 52 | import { | ||
| 53 | makeDenoSubprocessExecutor, | ||
| 54 | } from "@executor/runtime-deno-subprocess"; | ||
| 21 | 55 | ||
| 22 | import { | 56 | import { |
| 23 | type ResolveExecutionEnvironment, | 57 | type ResolveExecutionEnvironment, |
| 24 | } from "../index"; | 58 | } from "../index"; |
| 25 | import { createLocalExecutorRuntime as createExecutorRuntime } from "../../../../sdk-file/src/index"; | 59 | import { |
| 26 | import { withExecutorApiClient } from "./test-http-client"; | 60 | createLocalExecutorRuntime as createExecutorRuntime, |
| 61 | } from "../../../../sdk-file/src/index"; | ||
| 62 | import { | ||
| 63 | withExecutorApiClient, | ||
| 64 | } from "./test-http-client"; | ||
| 27 | 65 | ||
| 28 | type McpFormServer = { | 66 | type McpFormServer = { |
| 29 | endpoint: string; | 67 | endpoint: string; |
| @@ -290,16 +328,16 @@ describe("execution-mcp-resume", () => { · 260 unmodified lines | |||
| 290 | Effect.gen(function* () { | 328 | Effect.gen(function* () { |
| 291 | const mcpServer = yield* makeFormElicitationServer; | 329 | const mcpServer = yield* makeFormElicitationServer; |
| 292 | const fs = yield* FileSystem.FileSystem; | 330 | const fs = yield* FileSystem.FileSystem; |
| 293 | const workspaceRoot = yield* fs.makeTempDirectory({ | 331 | const scopeRoot = yield* fs.makeTempDirectory({ |
| 294 | directory: tmpdir(), | 332 | directory: tmpdir(), |
| 295 | prefix: "executor-execution-mcp-resume-", | 333 | prefix: "executor-execution-mcp-resume-", |
| 296 | }); | 334 | }); |
| 297 | const runtime = yield* Effect.acquireRelease( | 335 | const runtime = yield* Effect.acquireRelease( |
| 298 | createExecutorRuntime({ | 336 | createExecutorRuntime({ |
| 299 | localDataDir: ":memory:", | 337 | localDataDir: ":memory:", |
| 300 | workspaceRoot, | 338 | workspaceRoot: scopeRoot, |
| 301 | homeConfigPath: join(workspaceRoot, ".executor-home.jsonc"), | 339 | homeConfigPath: join(scopeRoot, ".executor-home.jsonc"), |
| 302 | homeStateDirectory: join(workspaceRoot, ".executor-home-state"), | 340 | homeStateDirectory: join(scopeRoot, ".executor-home-state"), |
| 303 | executionResolver: makeMcpExecutionResolver(mcpServer.endpoint), | 341 | executionResolver: makeMcpExecutionResolver(mcpServer.endpoint), |
| 304 | }), | 342 | }), |
| 305 | (runtime) => Effect.promise(() => runtime.close()).pipe(Effect.orDie), | 343 | (runtime) => Effect.promise(() => runtime.close()).pipe(Effect.orDie), |
| @@ -310,12 +348,12 @@ describe("execution-mcp-resume", () => { · 4 unmodified lines | |||
| 310 | const created = yield* withExecutorApiClient( | 348 | const created = yield* withExecutorApiClient( |
| 311 | { | 349 | { |
| 312 | runtime, | 350 | runtime, |
| 313 | accountId: installation.accountId, | 351 | actorScopeId: installation.actorScopeId, |
| 314 | }, | 352 | }, |
| 315 | (client) => | 353 | (client) => |
| 316 | client.executions.create({ | 354 | client.executions.create({ |
| 317 | path: { | 355 | path: { |
| 318 | workspaceId: installation.workspaceId, | 356 | scopeId: installation.scopeId, |
| 319 | }, | 357 | }, |
| 320 | payload: { | 358 | payload: { |
| 321 | code: 'return await tools.source.form.gated_echo({ value: "from-control-plane" });', | 359 | code: 'return await tools.source.form.gated_echo({ value: "from-control-plane" });', |
| @@ -344,12 +382,12 @@ describe("execution-mcp-resume", () => { · 22 unmodified lines | |||
| 344 | const resumed = yield* withExecutorApiClient( | 382 | const resumed = yield* withExecutorApiClient( |
| 345 | { | 383 | { |
| 346 | runtime, | 384 | runtime, |
| 347 | accountId: installation.accountId, | 385 | actorScopeId: installation.actorScopeId, |
| 348 | }, | 386 | }, |
| 349 | (client) => | 387 | (client) => |
| 350 | client.executions.resume({ | 388 | client.executions.resume({ |
| 351 | path: { | 389 | path: { |
| 352 | workspaceId: installation.workspaceId, | 390 | scopeId: installation.scopeId, |
| 353 | executionId: created.execution.id, | 391 | executionId: created.execution.id, |
| 354 | }, | 392 | }, |
| 355 | payload: { | 393 | payload: { |
| @@ -1,20 +1,36 @@ | |||
| 1 | import { tmpdir } from "node:os"; | 1 | import { |
| 2 | import { join } from "node:path"; | 2 | tmpdir, |
| 3 | import { FileSystem } from "@effect/platform"; | 3 | } from "node:os"; |
| 4 | import { NodeFileSystem } from "@effect/platform-node"; | 4 | import { |
| 5 | import { describe, expect, it } from "@effect/vitest"; | 5 | join, |
| 6 | } from "node:path"; | ||
| 7 | import { | ||
| 8 | FileSystem, | ||
| 9 | } from "@effect/platform"; | ||
| 10 | import { | ||
| 11 | NodeFileSystem, | ||
| 12 | } from "@effect/platform-node"; | ||
| 13 | import { | ||
| 14 | describe, | ||
| 15 | expect, | ||
| 16 | it, | ||
| 17 | } from "@effect/vitest"; | ||
| 6 | import * as Effect from "effect/Effect"; | 18 | import * as Effect from "effect/Effect"; |
| 7 | 19 | ||
| 8 | import { createLocalExecutorRuntime as createExecutorRuntime } from "../../../../sdk-file/src/index"; | 20 | import { |
| 9 | import { withExecutorApiClient } from "./test-http-client"; | 21 | createLocalExecutorRuntime as createExecutorRuntime, |
| 22 | } from "../../../../sdk-file/src/index"; | ||
| 23 | import { | ||
| 24 | withExecutorApiClient, | ||
| 25 | } from "./test-http-client"; | ||
| 10 | 26 | ||
| 11 | const writeProjectConfig = ( | 27 | const writeProjectConfig = ( |
| 12 | workspaceRoot: string, | 28 | scopeRoot: string, |
| 13 | config: Record<string, unknown>, | 29 | config: Record<string, unknown>, |
| 14 | ) => | 30 | ) => |
| 15 | Effect.gen(function* () { | 31 | Effect.gen(function* () { |
| 16 | const fs = yield* FileSystem.FileSystem; | 32 | const fs = yield* FileSystem.FileSystem; |
| 17 | const configDirectory = join(workspaceRoot, ".executor"); | 33 | const configDirectory = join(scopeRoot, ".executor"); |
| 18 | yield* fs.makeDirectory(configDirectory, { recursive: true }); | 34 | yield* fs.makeDirectory(configDirectory, { recursive: true }); |
| 19 | yield* fs.writeFileString( | 35 | yield* fs.writeFileString( |
| 20 | join(configDirectory, "executor.jsonc"), | 36 | join(configDirectory, "executor.jsonc"), |
| @@ -26,16 +42,16 @@ const makeRuntime = (config: Record<string, unknown>) => { · 5 unmodified lines | |||
| 26 | return Effect.acquireRelease( | 42 | return Effect.acquireRelease( |
| 27 | Effect.gen(function* () { | 43 | Effect.gen(function* () { |
| 28 | const fs = yield* FileSystem.FileSystem; | 44 | const fs = yield* FileSystem.FileSystem; |
| 29 | const workspaceRoot = yield* fs.makeTempDirectory({ | 45 | const scopeRoot = yield* fs.makeTempDirectory({ |
| 30 | directory: tmpdir(), | 46 | directory: tmpdir(), |
| 31 | prefix: "executor-runtime-config-", | 47 | prefix: "executor-runtime-config-", |
| 32 | }); | 48 | }); |
| 33 | yield* writeProjectConfig(workspaceRoot, config); | 49 | yield* writeProjectConfig(scopeRoot, config); |
| 34 | 50 | ||
| 35 | return yield* createExecutorRuntime({ | 51 | return yield* createExecutorRuntime({ |
| 36 | workspaceRoot, | 52 | workspaceRoot: scopeRoot, |
| 37 | homeConfigPath: join(workspaceRoot, ".executor-home.jsonc"), | 53 | homeConfigPath: join(scopeRoot, ".executor-home.jsonc"), |
| 38 | homeStateDirectory: join(workspaceRoot, ".executor-home-state"), | 54 | homeStateDirectory: join(scopeRoot, ".executor-home-state"), |
| 39 | }); | 55 | }); |
| 40 | }).pipe(Effect.provide(NodeFileSystem.layer)), | 56 | }).pipe(Effect.provide(NodeFileSystem.layer)), |
| 41 | (runtime) => Effect.promise(() => runtime.close()).pipe(Effect.orDie), | 57 | (runtime) => Effect.promise(() => runtime.close()).pipe(Effect.orDie), |
| @@ -53,12 +69,12 @@ describe("execution runtime config", () => { · 11 unmodified lines | |||
| 53 | const execution = yield* withExecutorApiClient( | 69 | const execution = yield* withExecutorApiClient( |
| 54 | { | 70 | { |
| 55 | runtime, | 71 | runtime, |
| 56 | accountId: installation.accountId, | 72 | actorScopeId: installation.actorScopeId, |
| 57 | }, | 73 | }, |
| 58 | (client) => | 74 | (client) => |
| 59 | client.executions.create({ | 75 | client.executions.create({ |
| 60 | path: { | 76 | path: { |
| 61 | workspaceId: installation.workspaceId, | 77 | scopeId: installation.scopeId, |
| 62 | }, | 78 | }, |
| 63 | payload: { | 79 | payload: { |
| 64 | code: 'await fetch("https://example.com"); return 1;', | 80 | code: 'await fetch("https://example.com"); return 1;', |
| @@ -85,12 +101,12 @@ describe("execution runtime config", () => { · 20 unmodified lines | |||
| 85 | const execution = yield* withExecutorApiClient( | 101 | const execution = yield* withExecutorApiClient( |
| 86 | { | 102 | { |
| 87 | runtime, | 103 | runtime, |
| 88 | accountId: installation.accountId, | 104 | actorScopeId: installation.actorScopeId, |
| 89 | }, | 105 | }, |
| 90 | (client) => | 106 | (client) => |
| 91 | client.executions.create({ | 107 | client.executions.create({ |
| 92 | path: { | 108 | path: { |
| 93 | workspaceId: installation.workspaceId, | 109 | scopeId: installation.scopeId, |
| 94 | }, | 110 | }, |
| 95 | payload: { | 111 | payload: { |
| 96 | code: 'await fetch("https://example.com"); return 1;', | 112 | code: 'await fetch("https://example.com"); return 1;', |
| @@ -117,12 +133,12 @@ describe("execution runtime config", () => { · 20 unmodified lines | |||
| 117 | const execution = yield* withExecutorApiClient( | 133 | const execution = yield* withExecutorApiClient( |
| 118 | { | 134 | { |
| 119 | runtime, | 135 | runtime, |
| 120 | accountId: installation.accountId, | 136 | actorScopeId: installation.actorScopeId, |
| 121 | }, | 137 | }, |
| 122 | (client) => | 138 | (client) => |
| 123 | client.executions.create({ | 139 | client.executions.create({ |
| 124 | path: { | 140 | path: { |
| 125 | workspaceId: installation.workspaceId, | 141 | scopeId: installation.scopeId, |
| 126 | }, | 142 | }, |
| 127 | payload: { | 143 | payload: { |
| 128 | code: 'return typeof Deno !== "undefined";', | 144 | code: 'return typeof Deno !== "undefined";', |
| @@ -1,8 +1,19 @@ | |||
| 1 | import type { CodeExecutor } from "@executor/codemode-core"; | 1 | import type { |
| 2 | import { makeDenoSubprocessExecutor } from "@executor/runtime-deno-subprocess"; | 2 | CodeExecutor, |
| 3 | import { makeQuickJsExecutor } from "@executor/runtime-quickjs"; | 3 | } from "@executor/codemode-core"; |
| 4 | import { makeSesExecutor } from "@executor/runtime-ses"; | 4 | import { |
| 5 | import type { LocalExecutorConfig, LocalExecutorRuntime } from "#schema"; | 5 | makeDenoSubprocessExecutor, |
| 6 | } from "@executor/runtime-deno-subprocess"; | ||
| 7 | import { | ||
| 8 | makeQuickJsExecutor, | ||
| 9 | } from "@executor/runtime-quickjs"; | ||
| 10 | import { | ||
| 11 | makeSesExecutor, | ||
| 12 | } from "@executor/runtime-ses"; | ||
| 13 | import type { | ||
| 14 | LocalExecutorConfig, | ||
| 15 | LocalExecutorRuntime, | ||
| 16 | } from "#schema"; | ||
| 6 | 17 | ||
| 7 | const DEFAULT_EXECUTION_RUNTIME: LocalExecutorRuntime = "quickjs"; | 18 | const DEFAULT_EXECUTION_RUNTIME: LocalExecutorRuntime = "quickjs"; |
| 8 | 19 | ||
| @@ -1,15 +1,32 @@ | |||
| 1 | import { type ToolPath, makeToolInvokerFromTools } from "@executor/codemode-core"; | 1 | import { |
| 2 | import type { Source } from "#schema"; | 2 | type ToolPath, |
| 3 | makeToolInvokerFromTools, | ||
| 4 | } from "@executor/codemode-core"; | ||
| 5 | import type { | ||
| 6 | Source, | ||
| 7 | } from "#schema"; | ||
| 3 | import * as Either from "effect/Either"; | 8 | import * as Either from "effect/Either"; |
| 4 | import * as Effect from "effect/Effect"; | 9 | import * as Effect from "effect/Effect"; |
| 5 | import * as Schema from "effect/Schema"; | 10 | import * as Schema from "effect/Schema"; |
| 6 | 11 | ||
| 7 | import type { LoadedSourceCatalogToolIndexEntry } from "../../catalog/source/runtime"; | 12 | import type { |
| 8 | import type { SecretMaterialResolveContext } from "../../workspace/secret-material-providers"; | 13 | LoadedSourceCatalogToolIndexEntry, |
| 9 | import type { WorkspaceStorageServices } from "../../workspace/storage"; | 14 | } from "../../catalog/source/runtime"; |
| 10 | import { invocationDescriptorFromTool } from "../ir-execution"; | 15 | import type { |
| 11 | import { evaluateInvocationPolicy } from "../../policy/invocation-policy-engine"; | 16 | SecretMaterialResolveContext, |
| 12 | import { loadRuntimeLocalWorkspacePolicies } from "../../../policies/operations"; | 17 | } from "../../scope/secret-material-providers"; |
| 18 | import type { | ||
| 19 | ScopeStorageServices, | ||
| 20 | } from "../../scope/storage"; | ||
| 21 | import { | ||
| 22 | invocationDescriptorFromTool, | ||
| 23 | } from "../ir-execution"; | ||
| 24 | import { | ||
| 25 | evaluateInvocationPolicy, | ||
| 26 | } from "../../policy/invocation-policy-engine"; | ||
| 27 | import { | ||
| 28 | loadRuntimeLocalScopePolicies, | ||
| 29 | } from "../../../policies/operations"; | ||
| 13 | 30 | ||
| 14 | const asToolPath = (value: string): ToolPath => value as ToolPath; | 31 | const asToolPath = (value: string): ToolPath => value as ToolPath; |
| 15 | 32 | ||
| @@ -64,23 +81,23 @@ export const toSecretResolutionContext = ( · 48 unmodified lines | |||
| 64 | const failAuthorization = (message: string): Effect.Effect<never, Error, never> => | 81 | const failAuthorization = (message: string): Effect.Effect<never, Error, never> => |
| 65 | Effect.fail(new Error(message)); | 82 | Effect.fail(new Error(message)); |
| 66 | 83 | ||
| 67 | type WorkspaceToolElicitation = Parameters< | 84 | type ScopeToolElicitation = Parameters< |
| 68 | typeof makeToolInvokerFromTools | 85 | typeof makeToolInvokerFromTools |
| 69 | >[0]["onElicitation"]; | 86 | >[0]["onElicitation"]; |
| 70 | 87 | ||
| 71 | export const authorizePersistedToolInvocation = (input: { | 88 | export const authorizePersistedToolInvocation = (input: { |
| 72 | workspaceId: Source["workspaceId"]; | 89 | scopeId: Source["scopeId"]; |
| 73 | tool: LoadedSourceCatalogToolIndexEntry; | 90 | tool: LoadedSourceCatalogToolIndexEntry; |
| 74 | args: unknown; | 91 | args: unknown; |
| 75 | context?: Record<string, unknown>; | 92 | context?: Record<string, unknown>; |
| 76 | onElicitation?: WorkspaceToolElicitation; | 93 | onElicitation?: ScopeToolElicitation; |
| 77 | }): Effect.Effect<void, Error, WorkspaceStorageServices> => | 94 | }): Effect.Effect<void, Error, ScopeStorageServices> => |
| 78 | Effect.gen(function* () { | 95 | Effect.gen(function* () { |
| 79 | const descriptor = invocationDescriptorFromTool({ | 96 | const descriptor = invocationDescriptorFromTool({ |
| 80 | tool: input.tool, | 97 | tool: input.tool, |
| 81 | }); | 98 | }); |
| 82 | const localWorkspacePolicies = yield* loadRuntimeLocalWorkspacePolicies( | 99 | const localScopePolicies = yield* loadRuntimeLocalScopePolicies( |
| 83 | input.workspaceId, | 100 | input.scopeId, |
| 84 | ).pipe( | 101 | ).pipe( |
| 85 | Effect.mapError((cause) => | 102 | Effect.mapError((cause) => |
| 86 | cause instanceof Error ? cause : new Error(String(cause)), | 103 | cause instanceof Error ? cause : new Error(String(cause)), |
| @@ -90,9 +107,9 @@ export const authorizePersistedToolInvocation = (input: { · 3 unmodified lines | |||
| 90 | const decision = evaluateInvocationPolicy({ | 107 | const decision = evaluateInvocationPolicy({ |
| 91 | descriptor, | 108 | descriptor, |
| 92 | args: input.args, | 109 | args: input.args, |
| 93 | policies: localWorkspacePolicies.policies, | 110 | policies: localScopePolicies.policies, |
| 94 | context: { | 111 | context: { |
| 95 | workspaceId: input.workspaceId, | 112 | scopeId: input.scopeId, |
| 96 | }, | 113 | }, |
| 97 | }); | 114 | }); |
| 98 | 115 | ||
| @@ -14,18 +14,30 @@ import { · 13 unmodified lines | |||
| 14 | createCodeExecutorForRuntime, | 14 | createCodeExecutorForRuntime, |
| 15 | resolveConfiguredExecutionRuntime, | 15 | resolveConfiguredExecutionRuntime, |
| 16 | } from "../runtime"; | 16 | } from "../runtime"; |
| 17 | import { createWorkspaceToolInvoker } from "./tool-invoker"; | 17 | import { |
| 18 | import { RuntimeSourceAuthServiceTag } from "../../sources/source-auth-service"; | 18 | createScopeToolInvoker, |
| 19 | import { RuntimeSourceCatalogStoreService } from "../../catalog/source/runtime"; | 19 | } from "./tool-invoker"; |
| 20 | import { RuntimeSourceAuthMaterialService } from "../../auth/source-auth-material"; | 20 | import { |
| 21 | import { RuntimeSourceCatalogSyncService } from "../../catalog/source/sync"; | 21 | RuntimeSourceAuthServiceTag, |
| 22 | import { getRuntimeLocalWorkspaceOption } from "../../workspace/runtime-context"; | 22 | } from "../../sources/source-auth-service"; |
| 23 | import { | ||
| 24 | RuntimeSourceCatalogStoreService, | ||
| 25 | } from "../../catalog/source/runtime"; | ||
| 26 | import { | ||
| 27 | RuntimeSourceAuthMaterialService, | ||
| 28 | } from "../../auth/source-auth-material"; | ||
| 29 | import { | ||
| 30 | RuntimeSourceCatalogSyncService, | ||
| 31 | } from "../../catalog/source/sync"; | ||
| 32 | import { | ||
| 33 | getRuntimeLocalScopeOption, | ||
| 34 | } from "../../scope/runtime-context"; | ||
| 23 | import { | 35 | import { |
| 24 | LocalInstanceConfigService, | 36 | LocalInstanceConfigService, |
| 25 | SecretMaterialDeleterService, | 37 | SecretMaterialDeleterService, |
| 26 | SecretMaterialStorerService, | 38 | SecretMaterialStorerService, |
| 27 | SecretMaterialUpdaterService, | 39 | SecretMaterialUpdaterService, |
| 28 | } from "../../workspace/secret-material-providers"; | 40 | } from "../../scope/secret-material-providers"; |
| 29 | import { | 41 | import { |
| 30 | LocalToolRuntimeLoaderService, | 42 | LocalToolRuntimeLoaderService, |
| 31 | type LocalToolRuntimeLoaderShape, | 43 | type LocalToolRuntimeLoaderShape, |
| @@ -36,14 +48,20 @@ import { · 4 unmodified lines | |||
| 36 | type InstallationStoreShape, | 48 | type InstallationStoreShape, |
| 37 | SourceArtifactStore, | 49 | SourceArtifactStore, |
| 38 | type SourceArtifactStoreShape, | 50 | type SourceArtifactStoreShape, |
| 39 | WorkspaceConfigStore, | 51 | ScopeConfigStore, |
| 40 | type WorkspaceConfigStoreShape, | 52 | type ScopeConfigStoreShape, |
| 41 | WorkspaceStateStore, | 53 | ScopeStateStore, |
| 42 | type WorkspaceStateStoreShape, | 54 | type ScopeStateStoreShape, |
| 43 | } from "../../workspace/storage"; | 55 | } from "../../scope/storage"; |
| 44 | import { ExecutorStateStore } from "../../executor-state-store"; | 56 | import { |
| 45 | import { RuntimeSourceStoreService } from "../../sources/source-store"; | 57 | ExecutorStateStore, |
| 46 | import type { CreateWorkspaceInternalToolMap } from "./tool-invoker"; | 58 | } from "../../executor-state-store"; |
| 59 | import { | ||
| 60 | RuntimeSourceStoreService, | ||
| 61 | } from "../../sources/source-store"; | ||
| 62 | import type { | ||
| 63 | CreateScopeInternalToolMap, | ||
| 64 | } from "./tool-invoker"; | ||
| 47 | export { | 65 | export { |
| 48 | createCodeExecutorForRuntime, | 66 | createCodeExecutorForRuntime, |
| 49 | resolveConfiguredExecutionRuntime, | 67 | resolveConfiguredExecutionRuntime, |
| @@ -56,7 +74,7 @@ const createEmptyLocalToolRuntime = (): LocalToolRuntime => ({ · 6 unmodified lines | |||
| 56 | toolPaths: new Set<string>(), | 74 | toolPaths: new Set<string>(), |
| 57 | }); | 75 | }); |
| 58 | 76 | ||
| 59 | export const createWorkspaceExecutionEnvironmentResolver = | 77 | export const createScopeExecutionEnvironmentResolver = |
| 60 | (input: { | 78 | (input: { |
| 61 | executorStateStore: Effect.Effect.Success<typeof ExecutorStateStore>; | 79 | executorStateStore: Effect.Effect.Success<typeof ExecutorStateStore>; |
| 62 | sourceStore: Effect.Effect.Success<typeof RuntimeSourceStoreService>; | 80 | sourceStore: Effect.Effect.Success<typeof RuntimeSourceStoreService>; |
| @@ -78,25 +96,25 @@ export const createWorkspaceExecutionEnvironmentResolver = · 15 unmodified lines | |||
| 78 | storeSecretMaterial: Effect.Effect.Success<typeof SecretMaterialStorerService>; | 96 | storeSecretMaterial: Effect.Effect.Success<typeof SecretMaterialStorerService>; |
| 79 | deleteSecretMaterial: Effect.Effect.Success<typeof SecretMaterialDeleterService>; | 97 | deleteSecretMaterial: Effect.Effect.Success<typeof SecretMaterialDeleterService>; |
| 80 | updateSecretMaterial: Effect.Effect.Success<typeof SecretMaterialUpdaterService>; | 98 | updateSecretMaterial: Effect.Effect.Success<typeof SecretMaterialUpdaterService>; |
| 81 | workspaceConfigStore: WorkspaceConfigStoreShape; | 99 | scopeConfigStore: ScopeConfigStoreShape; |
| 82 | workspaceStateStore: WorkspaceStateStoreShape; | 100 | scopeStateStore: ScopeStateStoreShape; |
| 83 | sourceArtifactStore: SourceArtifactStoreShape; | 101 | sourceArtifactStore: SourceArtifactStoreShape; |
| 84 | createInternalToolMap?: CreateWorkspaceInternalToolMap; | 102 | createInternalToolMap?: CreateScopeInternalToolMap; |
| 85 | }): ResolveExecutionEnvironment => | 103 | }): ResolveExecutionEnvironment => |
| 86 | ({ workspaceId, accountId, onElicitation }) => | 104 | ({ scopeId, actorScopeId, onElicitation }) => |
| 87 | Effect.gen(function* () { | 105 | Effect.gen(function* () { |
| 88 | const runtimeLocalWorkspace = yield* getRuntimeLocalWorkspaceOption(); | 106 | const runtimeLocalScope = yield* getRuntimeLocalScopeOption(); |
| 89 | const loadedConfig = | 107 | const loadedConfig = |
| 90 | runtimeLocalWorkspace === null | 108 | runtimeLocalScope === null |
| 91 | ? null | 109 | ? null |
| 92 | : yield* input.workspaceConfigStore.load(); | 110 | : yield* input.scopeConfigStore.load(); |
| 93 | const localToolRuntime = | 111 | const localToolRuntime = |
| 94 | runtimeLocalWorkspace === null | 112 | runtimeLocalScope === null |
| 95 | ? createEmptyLocalToolRuntime() | 113 | ? createEmptyLocalToolRuntime() |
| 96 | : yield* input.localToolRuntimeLoader.load(); | 114 | : yield* input.localToolRuntimeLoader.load(); |
| 97 | const { catalog, toolInvoker } = createWorkspaceToolInvoker({ | 115 | const { catalog, toolInvoker } = createScopeToolInvoker({ |
| 98 | workspaceId, | 116 | scopeId, |
| 99 | accountId, | 117 | actorScopeId, |
| 100 | executorStateStore: input.executorStateStore, | 118 | executorStateStore: input.executorStateStore, |
| 101 | sourceStore: input.sourceStore, | 119 | sourceStore: input.sourceStore, |
| 102 | sourceCatalogSyncService: input.sourceCatalogSyncService, | 120 | sourceCatalogSyncService: input.sourceCatalogSyncService, |
| @@ -106,12 +124,12 @@ export const createWorkspaceExecutionEnvironmentResolver = · 3 unmodified lines | |||
| 106 | storeSecretMaterial: input.storeSecretMaterial, | 124 | storeSecretMaterial: input.storeSecretMaterial, |
| 107 | deleteSecretMaterial: input.deleteSecretMaterial, | 125 | deleteSecretMaterial: input.deleteSecretMaterial, |
| 108 | updateSecretMaterial: input.updateSecretMaterial, | 126 | updateSecretMaterial: input.updateSecretMaterial, |
| 109 | workspaceConfigStore: input.workspaceConfigStore, | 127 | scopeConfigStore: input.scopeConfigStore, |
| 110 | workspaceStateStore: input.workspaceStateStore, | 128 | scopeStateStore: input.scopeStateStore, |
| 111 | sourceArtifactStore: input.sourceArtifactStore, | 129 | sourceArtifactStore: input.sourceArtifactStore, |
| 112 | sourceAuthMaterialService: input.sourceAuthMaterialService, | 130 | sourceAuthMaterialService: input.sourceAuthMaterialService, |
| 113 | sourceAuthService: input.sourceAuthService, | 131 | sourceAuthService: input.sourceAuthService, |
| 114 | runtimeLocalWorkspace, | 132 | runtimeLocalScope, |
| 115 | localToolRuntime, | 133 | localToolRuntime, |
| 116 | createInternalToolMap: input.createInternalToolMap, | 134 | createInternalToolMap: input.createInternalToolMap, |
| 117 | onElicitation, | 135 | onElicitation, |
| @@ -132,13 +150,13 @@ export class RuntimeExecutionResolverService extends Context.Tag( · 14 unmodified lines | |||
| 132 | "#runtime/RuntimeExecutionResolverService", | 150 | "#runtime/RuntimeExecutionResolverService", |
| 133 | )< | 151 | )< |
| 134 | RuntimeExecutionResolverService, | 152 | RuntimeExecutionResolverService, |
| 135 | ReturnType<typeof createWorkspaceExecutionEnvironmentResolver> | 153 | ReturnType<typeof createScopeExecutionEnvironmentResolver> |
| 136 | >() {} | 154 | >() {} |
| 137 | 155 | ||
| 138 | export const RuntimeExecutionResolverLive = ( | 156 | export const RuntimeExecutionResolverLive = ( |
| 139 | input: { | 157 | input: { |
| 140 | executionResolver?: ResolveExecutionEnvironment; | 158 | executionResolver?: ResolveExecutionEnvironment; |
| 141 | createInternalToolMap?: CreateWorkspaceInternalToolMap; | 159 | createInternalToolMap?: CreateScopeInternalToolMap; |
| 142 | } = {}, | 160 | } = {}, |
| 143 | ) => | 161 | ) => |
| 144 | input.executionResolver | 162 | input.executionResolver |
| @@ -160,11 +178,11 @@ export const RuntimeExecutionResolverLive = ( · 15 unmodified lines | |||
| 160 | const storeSecretMaterial = yield* SecretMaterialStorerService; | 178 | const storeSecretMaterial = yield* SecretMaterialStorerService; |
| 161 | const deleteSecretMaterial = yield* SecretMaterialDeleterService; | 179 | const deleteSecretMaterial = yield* SecretMaterialDeleterService; |
| 162 | const updateSecretMaterial = yield* SecretMaterialUpdaterService; | 180 | const updateSecretMaterial = yield* SecretMaterialUpdaterService; |
| 163 | const workspaceConfigStore = yield* WorkspaceConfigStore; | 181 | const scopeConfigStore = yield* ScopeConfigStore; |
| 164 | const workspaceStateStore = yield* WorkspaceStateStore; | 182 | const scopeStateStore = yield* ScopeStateStore; |
| 165 | const sourceArtifactStore = yield* SourceArtifactStore; | 183 | const sourceArtifactStore = yield* SourceArtifactStore; |
| 166 | 184 | ||
| 167 | return createWorkspaceExecutionEnvironmentResolver({ | 185 | return createScopeExecutionEnvironmentResolver({ |
| 168 | executorStateStore, | 186 | executorStateStore, |
| 169 | sourceStore, | 187 | sourceStore, |
| 170 | sourceCatalogSyncService, | 188 | sourceCatalogSyncService, |
| @@ -177,8 +195,8 @@ export const RuntimeExecutionResolverLive = ( · 6 unmodified lines | |||
| 177 | storeSecretMaterial, | 195 | storeSecretMaterial, |
| 178 | deleteSecretMaterial, | 196 | deleteSecretMaterial, |
| 179 | updateSecretMaterial, | 197 | updateSecretMaterial, |
| 180 | workspaceConfigStore, | 198 | scopeConfigStore, |
| 181 | workspaceStateStore, | 199 | scopeStateStore, |
| 182 | sourceArtifactStore, | 200 | sourceArtifactStore, |
| 183 | createInternalToolMap: input.createInternalToolMap, | 201 | createInternalToolMap: input.createInternalToolMap, |
| 184 | }); | 202 | }); |
| @@ -0,0 +1,12 @@ | |||
| 1 | import * as Effect from "effect/Effect"; | ||
| 2 | |||
| 3 | import { | ||
| 4 | provideOptionalRuntimeLocalScope, | ||
| 5 | type RuntimeLocalScopeState, | ||
| 6 | } from "../../scope/runtime-context"; | ||
| 7 | |||
| 8 | export const provideRuntimeLocalScope = <A, E, R>( | ||
| 9 | effect: Effect.Effect<A, E, R>, | ||
| 10 | runtimeLocalScope: RuntimeLocalScopeState | null, | ||
| 11 | ): Effect.Effect<A, E, R> => | ||
| 12 | provideOptionalRuntimeLocalScope(effect, runtimeLocalScope); | ||
| @@ -2,7 +2,10 @@ import { · 1 unmodified line | |||
| 2 | createToolCatalogFromEntries, | 2 | createToolCatalogFromEntries, |
| 3 | type ToolCatalog, | 3 | type ToolCatalog, |
| 4 | } from "@executor/codemode-core"; | 4 | } from "@executor/codemode-core"; |
| 5 | import type { AccountId, Source } from "#schema"; | 5 | import type { |
| 6 | ScopeId, | ||
| 7 | Source, | ||
| 8 | } from "#schema"; | ||
| 6 | import * as Effect from "effect/Effect"; | 9 | import * as Effect from "effect/Effect"; |
| 7 | 10 | ||
| 8 | import { | 11 | import { |
| @@ -10,15 +13,19 @@ import { · 1 unmodified line | |||
| 10 | type LoadedSourceCatalogToolIndexEntry, | 13 | type LoadedSourceCatalogToolIndexEntry, |
| 11 | catalogToolCatalogEntry, | 14 | catalogToolCatalogEntry, |
| 12 | } from "../../catalog/source/runtime"; | 15 | } from "../../catalog/source/runtime"; |
| 13 | import type { RuntimeLocalWorkspaceState } from "../../workspace/runtime-context"; | 16 | import type { |
| 17 | RuntimeLocalScopeState, | ||
| 18 | } from "../../scope/runtime-context"; | ||
| 14 | import { | 19 | import { |
| 15 | makeWorkspaceStorageLayer, | 20 | makeScopeStorageLayer, |
| 16 | type SourceArtifactStoreShape, | 21 | type SourceArtifactStoreShape, |
| 17 | type WorkspaceConfigStoreShape, | 22 | type ScopeConfigStoreShape, |
| 18 | type WorkspaceStateStoreShape, | 23 | type ScopeStateStoreShape, |
| 19 | type WorkspaceStorageServices, | 24 | type ScopeStorageServices, |
| 20 | } from "../../workspace/storage"; | 25 | } from "../../scope/storage"; |
| 21 | import { provideRuntimeLocalWorkspace } from "./local"; | 26 | import { |
| 27 | provideRuntimeLocalScope, | ||
| 28 | } from "./local"; | ||
| 22 | 29 | ||
| 23 | const tokenize = (value: string): string[] => | 30 | const tokenize = (value: string): string[] => |
| 24 | value | 31 | value |
| @@ -74,19 +81,19 @@ const queryTokenWeight = (token: string): number => · 49 unmodified lines | |||
| 74 | LOW_SIGNAL_QUERY_TOKENS.has(token) ? 0.25 : 1; | 81 | LOW_SIGNAL_QUERY_TOKENS.has(token) ? 0.25 : 1; |
| 75 | 82 | ||
| 76 | export const loadWorkspaceCatalogTools = (input: { | 83 | export const loadWorkspaceCatalogTools = (input: { |
| 77 | workspaceId: Source["workspaceId"]; | 84 | scopeId: Source["scopeId"]; |
| 78 | accountId: AccountId; | 85 | actorScopeId: ScopeId; |
| 79 | sourceCatalogStore: Effect.Effect.Success<typeof RuntimeSourceCatalogStoreService>; | 86 | sourceCatalogStore: Effect.Effect.Success<typeof RuntimeSourceCatalogStoreService>; |
| 80 | includeSchemas: boolean; | 87 | includeSchemas: boolean; |
| 81 | }): Effect.Effect< | 88 | }): Effect.Effect< |
| 82 | readonly LoadedSourceCatalogToolIndexEntry[], | 89 | readonly LoadedSourceCatalogToolIndexEntry[], |
| 83 | Error, | 90 | Error, |
| 84 | WorkspaceStorageServices | 91 | ScopeStorageServices |
| 85 | > => | 92 | > => |
| 86 | Effect.map( | 93 | Effect.map( |
| 87 | input.sourceCatalogStore.loadWorkspaceSourceCatalogToolIndex({ | 94 | input.sourceCatalogStore.loadWorkspaceSourceCatalogToolIndex({ |
| 88 | workspaceId: input.workspaceId, | 95 | scopeId: input.scopeId, |
| 89 | actorAccountId: input.accountId, | 96 | actorScopeId: input.actorScopeId, |
| 90 | includeSchemas: input.includeSchemas, | 97 | includeSchemas: input.includeSchemas, |
| 91 | }), | 98 | }), |
| 92 | (tools) => | 99 | (tools) => |
| @@ -96,20 +103,20 @@ export const loadWorkspaceCatalogTools = (input: { · 3 unmodified lines | |||
| 96 | ); | 103 | ); |
| 97 | 104 | ||
| 98 | export const loadWorkspaceCatalogToolByPath = (input: { | 105 | export const loadWorkspaceCatalogToolByPath = (input: { |
| 99 | workspaceId: Source["workspaceId"]; | 106 | scopeId: Source["scopeId"]; |
| 100 | accountId: AccountId; | 107 | actorScopeId: ScopeId; |
| 101 | sourceCatalogStore: Effect.Effect.Success<typeof RuntimeSourceCatalogStoreService>; | 108 | sourceCatalogStore: Effect.Effect.Success<typeof RuntimeSourceCatalogStoreService>; |
| 102 | path: string; | 109 | path: string; |
| 103 | includeSchemas: boolean; | 110 | includeSchemas: boolean; |
| 104 | }): Effect.Effect< | 111 | }): Effect.Effect< |
| 105 | LoadedSourceCatalogToolIndexEntry | null, | 112 | LoadedSourceCatalogToolIndexEntry | null, |
| 106 | Error, | 113 | Error, |
| 107 | WorkspaceStorageServices | 114 | ScopeStorageServices |
| 108 | > => | 115 | > => |
| 109 | input.sourceCatalogStore.loadWorkspaceSourceCatalogToolByPath({ | 116 | input.sourceCatalogStore.loadWorkspaceSourceCatalogToolByPath({ |
| 110 | workspaceId: input.workspaceId, | 117 | scopeId: input.scopeId, |
| 111 | path: input.path, | 118 | path: input.path, |
| 112 | actorAccountId: input.accountId, | 119 | actorScopeId: input.actorScopeId, |
| 113 | includeSchemas: input.includeSchemas, | 120 | includeSchemas: input.includeSchemas, |
| 114 | }).pipe( | 121 | }).pipe( |
| 115 | Effect.map((tool) => | 122 | Effect.map((tool) => |
| @@ -245,28 +252,28 @@ const scoreCatalogTool = ( · 129 unmodified lines | |||
| 245 | return score; | 252 | return score; |
| 246 | }; | 253 | }; |
| 247 | 254 | ||
| 248 | export const createWorkspaceSourceCatalog = (input: { | 255 | export const createScopeSourceCatalog = (input: { |
| 249 | workspaceId: Source["workspaceId"]; | 256 | scopeId: Source["scopeId"]; |
| 250 | accountId: AccountId; | 257 | actorScopeId: ScopeId; |
| 251 | sourceCatalogStore: Effect.Effect.Success<typeof RuntimeSourceCatalogStoreService>; | 258 | sourceCatalogStore: Effect.Effect.Success<typeof RuntimeSourceCatalogStoreService>; |
| 252 | workspaceConfigStore: WorkspaceConfigStoreShape; | 259 | scopeConfigStore: ScopeConfigStoreShape; |
| 253 | workspaceStateStore: WorkspaceStateStoreShape; | 260 | scopeStateStore: ScopeStateStoreShape; |
| 254 | sourceArtifactStore: SourceArtifactStoreShape; | 261 | sourceArtifactStore: SourceArtifactStoreShape; |
| 255 | runtimeLocalWorkspace: RuntimeLocalWorkspaceState | null; | 262 | runtimeLocalScope: RuntimeLocalScopeState | null; |
| 256 | }): ToolCatalog => { | 263 | }): ToolCatalog => { |
| 257 | const workspaceStorageLayer = makeWorkspaceStorageLayer({ | 264 | const scopeStorageLayer = makeScopeStorageLayer({ |
| 258 | workspaceConfigStore: input.workspaceConfigStore, | 265 | scopeConfigStore: input.scopeConfigStore, |
| 259 | workspaceStateStore: input.workspaceStateStore, | 266 | scopeStateStore: input.scopeStateStore, |
| 260 | sourceArtifactStore: input.sourceArtifactStore, | 267 | sourceArtifactStore: input.sourceArtifactStore, |
| 261 | }); | 268 | }); |
| 262 | const provideWorkspaceStorage = <A, E, R>(effect: Effect.Effect<A, E, R>) => | 269 | const provideWorkspaceStorage = <A, E, R>(effect: Effect.Effect<A, E, R>) => |
| 263 | effect.pipe(Effect.provide(workspaceStorageLayer)); | 270 | effect.pipe(Effect.provide(scopeStorageLayer)); |
| 264 | 271 | ||
| 265 | const createSharedCatalog = (includeSchemas: boolean): Effect.Effect<ToolCatalog, Error, never> => | 272 | const createSharedCatalog = (includeSchemas: boolean): Effect.Effect<ToolCatalog, Error, never> => |
| 266 | provideWorkspaceStorage(Effect.gen(function* () { | 273 | provideWorkspaceStorage(Effect.gen(function* () { |
| 267 | const catalogTools = yield* loadWorkspaceCatalogTools({ | 274 | const catalogTools = yield* loadWorkspaceCatalogTools({ |
| 268 | workspaceId: input.workspaceId, | 275 | scopeId: input.scopeId, |
| 269 | accountId: input.accountId, | 276 | actorScopeId: input.actorScopeId, |
| 270 | sourceCatalogStore: input.sourceCatalogStore, | 277 | sourceCatalogStore: input.sourceCatalogStore, |
| 271 | includeSchemas, | 278 | includeSchemas, |
| 272 | }); | 279 | }); |
| @@ -283,15 +290,15 @@ export const createWorkspaceSourceCatalog = (input: { · 10 unmodified lines | |||
| 283 | 290 | ||
| 284 | return { | 291 | return { |
| 285 | listNamespaces: ({ limit }) => | 292 | listNamespaces: ({ limit }) => |
| 286 | provideRuntimeLocalWorkspace( | 293 | provideRuntimeLocalScope( |
| 287 | Effect.flatMap(createSharedCatalog(false), (catalog) => | 294 | Effect.flatMap(createSharedCatalog(false), (catalog) => |
| 288 | catalog.listNamespaces({ limit }), | 295 | catalog.listNamespaces({ limit }), |
| 289 | ), | 296 | ), |
| 290 | input.runtimeLocalWorkspace, | 297 | input.runtimeLocalScope, |
| 291 | ), | 298 | ), |
| 292 | 299 | ||
| 293 | listTools: ({ namespace, query, limit, includeSchemas = false }) => | 300 | listTools: ({ namespace, query, limit, includeSchemas = false }) => |
| 294 | provideRuntimeLocalWorkspace( | 301 | provideRuntimeLocalScope( |
| 295 | Effect.flatMap(createSharedCatalog(includeSchemas), (catalog) => | 302 | Effect.flatMap(createSharedCatalog(includeSchemas), (catalog) => |
| 296 | catalog.listTools({ | 303 | catalog.listTools({ |
| 297 | ...(namespace !== undefined ? { namespace } : {}), | 304 | ...(namespace !== undefined ? { namespace } : {}), |
| @@ -300,19 +307,19 @@ export const createWorkspaceSourceCatalog = (input: { · 2 unmodified lines | |||
| 300 | includeSchemas, | 307 | includeSchemas, |
| 301 | }), | 308 | }), |
| 302 | ), | 309 | ), |
| 303 | input.runtimeLocalWorkspace, | 310 | input.runtimeLocalScope, |
| 304 | ), | 311 | ), |
| 305 | 312 | ||
| 306 | getToolByPath: ({ path, includeSchemas }) => | 313 | getToolByPath: ({ path, includeSchemas }) => |
| 307 | provideRuntimeLocalWorkspace( | 314 | provideRuntimeLocalScope( |
| 308 | Effect.flatMap(createSharedCatalog(includeSchemas), (catalog) => | 315 | Effect.flatMap(createSharedCatalog(includeSchemas), (catalog) => |
| 309 | catalog.getToolByPath({ path, includeSchemas }), | 316 | catalog.getToolByPath({ path, includeSchemas }), |
| 310 | ), | 317 | ), |
| 311 | input.runtimeLocalWorkspace, | 318 | input.runtimeLocalScope, |
| 312 | ), | 319 | ), |
| 313 | 320 | ||
| 314 | searchTools: ({ query, namespace, limit }) => | 321 | searchTools: ({ query, namespace, limit }) => |
| 315 | provideRuntimeLocalWorkspace( | 322 | provideRuntimeLocalScope( |
| 316 | Effect.flatMap(createSharedCatalog(false), (catalog) => | 323 | Effect.flatMap(createSharedCatalog(false), (catalog) => |
| 317 | catalog.searchTools({ | 324 | catalog.searchTools({ |
| 318 | query, | 325 | query, |
| @@ -320,7 +327,7 @@ export const createWorkspaceSourceCatalog = (input: { · 1 unmodified line | |||
| 320 | limit, | 327 | limit, |
| 321 | }), | 328 | }), |
| 322 | ), | 329 | ), |
| 323 | input.runtimeLocalWorkspace, | 330 | input.runtimeLocalScope, |
| 324 | ), | 331 | ), |
| 325 | } satisfies ToolCatalog; | 332 | } satisfies ToolCatalog; |
| 326 | }; | 333 | }; |
| @@ -8,46 +8,73 @@ import { · 7 unmodified lines | |||
| 8 | type ToolMap, | 8 | type ToolMap, |
| 9 | type ToolInvoker, | 9 | type ToolInvoker, |
| 10 | } from "@executor/codemode-core"; | 10 | } from "@executor/codemode-core"; |
| 11 | import type { AccountId, Source } from "#schema"; | 11 | import type { |
| 12 | ScopeId, | ||
| 13 | Source, | ||
| 14 | } from "#schema"; | ||
| 12 | import * as Effect from "effect/Effect"; | 15 | import * as Effect from "effect/Effect"; |
| 13 | 16 | ||
| 14 | import { RuntimeSourceAuthMaterialService } from "../../auth/source-auth-material"; | 17 | import { |
| 15 | import { RuntimeSourceCatalogStoreService } from "../../catalog/source/runtime"; | 18 | RuntimeSourceAuthMaterialService, |
| 16 | import type { RuntimeLocalWorkspaceState } from "../../workspace/runtime-context"; | 19 | } from "../../auth/source-auth-material"; |
| 17 | import { type LocalToolRuntime } from "../../local-tool-runtime"; | 20 | import { |
| 21 | RuntimeSourceCatalogStoreService, | ||
| 22 | } from "../../catalog/source/runtime"; | ||
| 23 | import type { | ||
| 24 | RuntimeLocalScopeState, | ||
| 25 | } from "../../scope/runtime-context"; | ||
| 26 | import { | ||
| 27 | type LocalToolRuntime, | ||
| 28 | } from "../../local-tool-runtime"; | ||
| 18 | import { | 29 | import { |
| 19 | type InstallationStoreShape, | 30 | type InstallationStoreShape, |
| 20 | makeWorkspaceStorageLayer, | 31 | makeScopeStorageLayer, |
| 21 | type SourceArtifactStoreShape, | 32 | type SourceArtifactStoreShape, |
| 22 | type WorkspaceConfigStoreShape, | 33 | type ScopeConfigStoreShape, |
| 23 | type WorkspaceStateStoreShape, | 34 | type ScopeStateStoreShape, |
| 24 | } from "../../workspace/storage"; | 35 | } from "../../scope/storage"; |
| 25 | import type { | 36 | import type { |
| 26 | DeleteSecretMaterial, | 37 | DeleteSecretMaterial, |
| 27 | ResolveInstanceConfig, | 38 | ResolveInstanceConfig, |
| 28 | StoreSecretMaterial, | 39 | StoreSecretMaterial, |
| 29 | UpdateSecretMaterial, | 40 | UpdateSecretMaterial, |
| 30 | } from "../../workspace/secret-material-providers"; | 41 | } from "../../scope/secret-material-providers"; |
| 31 | import type { ExecutorStateStoreShape } from "../../executor-state-store"; | 42 | import type { |
| 32 | import { RuntimeSourceAuthService } from "../../sources/source-auth-service"; | 43 | ExecutorStateStoreShape, |
| 33 | import { type RuntimeSourceStore } from "../../sources/source-store"; | 44 | } from "../../executor-state-store"; |
| 34 | import { createExecutorToolMap } from "../../sources/executor-tools"; | 45 | import { |
| 35 | import { RuntimeSourceCatalogSyncService } from "../../catalog/source/sync"; | 46 | RuntimeSourceAuthService, |
| 36 | import { invokeIrTool } from "../ir-execution"; | 47 | } from "../../sources/source-auth-service"; |
| 48 | import { | ||
| 49 | type RuntimeSourceStore, | ||
| 50 | } from "../../sources/source-store"; | ||
| 51 | import { | ||
| 52 | createExecutorToolMap, | ||
| 53 | } from "../../sources/executor-tools"; | ||
| 54 | import { | ||
| 55 | RuntimeSourceCatalogSyncService, | ||
| 56 | } from "../../catalog/source/sync"; | ||
| 57 | import { | ||
| 58 | invokeIrTool, | ||
| 59 | } from "../ir-execution"; | ||
| 37 | import { | 60 | import { |
| 38 | authorizePersistedToolInvocation, | 61 | authorizePersistedToolInvocation, |
| 39 | toSecretResolutionContext, | 62 | toSecretResolutionContext, |
| 40 | } from "./authorization"; | 63 | } from "./authorization"; |
| 41 | import { provideRuntimeLocalWorkspace } from "./local"; | ||
| 42 | import { | 64 | import { |
| 43 | createWorkspaceSourceCatalog, | 65 | provideRuntimeLocalScope, |
| 66 | } from "./local"; | ||
| 67 | import { | ||
| 68 | createScopeSourceCatalog, | ||
| 44 | loadWorkspaceCatalogToolByPath, | 69 | loadWorkspaceCatalogToolByPath, |
| 45 | } from "./source-catalog"; | 70 | } from "./source-catalog"; |
| 46 | import { runtimeEffectError } from "../../effect-errors"; | 71 | import { |
| 72 | runtimeEffectError, | ||
| 73 | } from "../../effect-errors"; | ||
| 47 | 74 | ||
| 48 | export type WorkspaceInternalToolContext = { | 75 | export type ScopeInternalToolContext = { |
| 49 | workspaceId: Source["workspaceId"]; | 76 | scopeId: Source["scopeId"]; |
| 50 | accountId: AccountId; | 77 | actorScopeId: ScopeId; |
| 51 | executorStateStore: ExecutorStateStoreShape; | 78 | executorStateStore: ExecutorStateStoreShape; |
| 52 | sourceStore: RuntimeSourceStore; | 79 | sourceStore: RuntimeSourceStore; |
| 53 | sourceCatalogSyncService: Effect.Effect.Success< | 80 | sourceCatalogSyncService: Effect.Effect.Success< |
| @@ -59,19 +86,19 @@ export type WorkspaceInternalToolContext = { · 5 unmodified lines | |||
| 59 | storeSecretMaterial: StoreSecretMaterial; | 86 | storeSecretMaterial: StoreSecretMaterial; |
| 60 | deleteSecretMaterial: DeleteSecretMaterial; | 87 | deleteSecretMaterial: DeleteSecretMaterial; |
| 61 | updateSecretMaterial: UpdateSecretMaterial; | 88 | updateSecretMaterial: UpdateSecretMaterial; |
| 62 | workspaceConfigStore: WorkspaceConfigStoreShape; | 89 | scopeConfigStore: ScopeConfigStoreShape; |
| 63 | workspaceStateStore: WorkspaceStateStoreShape; | 90 | scopeStateStore: ScopeStateStoreShape; |
| 64 | sourceArtifactStore: SourceArtifactStoreShape; | 91 | sourceArtifactStore: SourceArtifactStoreShape; |
| 65 | runtimeLocalWorkspace: RuntimeLocalWorkspaceState | null; | 92 | runtimeLocalScope: RuntimeLocalScopeState | null; |
| 66 | }; | 93 | }; |
| 67 | 94 | ||
| 68 | export type CreateWorkspaceInternalToolMap = ( | 95 | export type CreateScopeInternalToolMap = ( |
| 69 | input: WorkspaceInternalToolContext, | 96 | input: ScopeInternalToolContext, |
| 70 | ) => ToolMap; | 97 | ) => ToolMap; |
| 71 | 98 | ||
| 72 | export const createWorkspaceToolInvoker = (input: { | 99 | export const createScopeToolInvoker = (input: { |
| 73 | workspaceId: Source["workspaceId"]; | 100 | scopeId: Source["scopeId"]; |
| 74 | accountId: AccountId; | 101 | actorScopeId: ScopeId; |
| 75 | executorStateStore: ExecutorStateStoreShape; | 102 | executorStateStore: ExecutorStateStoreShape; |
| 76 | sourceStore: RuntimeSourceStore; | 103 | sourceStore: RuntimeSourceStore; |
| 77 | sourceCatalogSyncService: Effect.Effect.Success< | 104 | sourceCatalogSyncService: Effect.Effect.Success< |
| @@ -85,16 +112,16 @@ export const createWorkspaceToolInvoker = (input: { · 7 unmodified lines | |||
| 85 | storeSecretMaterial: StoreSecretMaterial; | 112 | storeSecretMaterial: StoreSecretMaterial; |
| 86 | deleteSecretMaterial: DeleteSecretMaterial; | 113 | deleteSecretMaterial: DeleteSecretMaterial; |
| 87 | updateSecretMaterial: UpdateSecretMaterial; | 114 | updateSecretMaterial: UpdateSecretMaterial; |
| 88 | workspaceConfigStore: WorkspaceConfigStoreShape; | 115 | scopeConfigStore: ScopeConfigStoreShape; |
| 89 | workspaceStateStore: WorkspaceStateStoreShape; | 116 | scopeStateStore: ScopeStateStoreShape; |
| 90 | sourceArtifactStore: SourceArtifactStoreShape; | 117 | sourceArtifactStore: SourceArtifactStoreShape; |
| 91 | sourceAuthMaterialService: Effect.Effect.Success< | 118 | sourceAuthMaterialService: Effect.Effect.Success< |
| 92 | typeof RuntimeSourceAuthMaterialService | 119 | typeof RuntimeSourceAuthMaterialService |
| 93 | >; | 120 | >; |
| 94 | sourceAuthService: RuntimeSourceAuthService; | 121 | sourceAuthService: RuntimeSourceAuthService; |
| 95 | runtimeLocalWorkspace: RuntimeLocalWorkspaceState | null; | 122 | runtimeLocalScope: RuntimeLocalScopeState | null; |
| 96 | localToolRuntime: LocalToolRuntime; | 123 | localToolRuntime: LocalToolRuntime; |
| 97 | createInternalToolMap?: CreateWorkspaceInternalToolMap; | 124 | createInternalToolMap?: CreateScopeInternalToolMap; |
| 98 | onElicitation?: Parameters< | 125 | onElicitation?: Parameters< |
| 99 | typeof makeToolInvokerFromTools | 126 | typeof makeToolInvokerFromTools |
| 100 | >[0]["onElicitation"]; | 127 | >[0]["onElicitation"]; |
| @@ -102,28 +129,28 @@ export const createWorkspaceToolInvoker = (input: { · 1 unmodified line | |||
| 102 | catalog: ToolCatalog; | 129 | catalog: ToolCatalog; |
| 103 | toolInvoker: ToolInvoker; | 130 | toolInvoker: ToolInvoker; |
| 104 | } => { | 131 | } => { |
| 105 | const workspaceStorageLayer = makeWorkspaceStorageLayer({ | 132 | const scopeStorageLayer = makeScopeStorageLayer({ |
| 106 | workspaceConfigStore: input.workspaceConfigStore, | 133 | scopeConfigStore: input.scopeConfigStore, |
| 107 | workspaceStateStore: input.workspaceStateStore, | 134 | scopeStateStore: input.scopeStateStore, |
| 108 | sourceArtifactStore: input.sourceArtifactStore, | 135 | sourceArtifactStore: input.sourceArtifactStore, |
| 109 | }); | 136 | }); |
| 110 | const provideWorkspaceStorage = <A, E, R>(effect: Effect.Effect<A, E, R>) => | 137 | const provideWorkspaceStorage = <A, E, R>(effect: Effect.Effect<A, E, R>) => |
| 111 | effect.pipe(Effect.provide(workspaceStorageLayer)); | 138 | effect.pipe(Effect.provide(scopeStorageLayer)); |
| 112 | 139 | ||
| 113 | const executorTools = createExecutorToolMap({ | 140 | const executorTools = createExecutorToolMap({ |
| 114 | workspaceId: input.workspaceId, | 141 | scopeId: input.scopeId, |
| 115 | accountId: input.accountId, | 142 | actorScopeId: input.actorScopeId, |
| 116 | sourceAuthService: input.sourceAuthService, | 143 | sourceAuthService: input.sourceAuthService, |
| 117 | installationStore: input.installationStore, | 144 | installationStore: input.installationStore, |
| 118 | workspaceConfigStore: input.workspaceConfigStore, | 145 | scopeConfigStore: input.scopeConfigStore, |
| 119 | workspaceStateStore: input.workspaceStateStore, | 146 | scopeStateStore: input.scopeStateStore, |
| 120 | sourceArtifactStore: input.sourceArtifactStore, | 147 | sourceArtifactStore: input.sourceArtifactStore, |
| 121 | runtimeLocalWorkspace: input.runtimeLocalWorkspace, | 148 | runtimeLocalScope: input.runtimeLocalScope, |
| 122 | }); | 149 | }); |
| 123 | const internalTools = | 150 | const internalTools = |
| 124 | input.createInternalToolMap?.({ | 151 | input.createInternalToolMap?.({ |
| 125 | workspaceId: input.workspaceId, | 152 | scopeId: input.scopeId, |
| 126 | accountId: input.accountId, | 153 | actorScopeId: input.actorScopeId, |
| 127 | executorStateStore: input.executorStateStore, | 154 | executorStateStore: input.executorStateStore, |
| 128 | sourceStore: input.sourceStore, | 155 | sourceStore: input.sourceStore, |
| 129 | sourceCatalogSyncService: input.sourceCatalogSyncService, | 156 | sourceCatalogSyncService: input.sourceCatalogSyncService, |
| @@ -133,19 +160,19 @@ export const createWorkspaceToolInvoker = (input: { · 3 unmodified lines | |||
| 133 | storeSecretMaterial: input.storeSecretMaterial, | 160 | storeSecretMaterial: input.storeSecretMaterial, |
| 134 | deleteSecretMaterial: input.deleteSecretMaterial, | 161 | deleteSecretMaterial: input.deleteSecretMaterial, |
| 135 | updateSecretMaterial: input.updateSecretMaterial, | 162 | updateSecretMaterial: input.updateSecretMaterial, |
| 136 | workspaceConfigStore: input.workspaceConfigStore, | 163 | scopeConfigStore: input.scopeConfigStore, |
| 137 | workspaceStateStore: input.workspaceStateStore, | 164 | scopeStateStore: input.scopeStateStore, |
| 138 | sourceArtifactStore: input.sourceArtifactStore, | 165 | sourceArtifactStore: input.sourceArtifactStore, |
| 139 | runtimeLocalWorkspace: input.runtimeLocalWorkspace, | 166 | runtimeLocalScope: input.runtimeLocalScope, |
| 140 | }) ?? {}; | 167 | }) ?? {}; |
| 141 | const sourceCatalog = createWorkspaceSourceCatalog({ | 168 | const sourceCatalog = createScopeSourceCatalog({ |
| 142 | workspaceId: input.workspaceId, | 169 | scopeId: input.scopeId, |
| 143 | accountId: input.accountId, | 170 | actorScopeId: input.actorScopeId, |
| 144 | sourceCatalogStore: input.sourceCatalogStore, | 171 | sourceCatalogStore: input.sourceCatalogStore, |
| 145 | workspaceConfigStore: input.workspaceConfigStore, | 172 | scopeConfigStore: input.scopeConfigStore, |
| 146 | workspaceStateStore: input.workspaceStateStore, | 173 | scopeStateStore: input.scopeStateStore, |
| 147 | sourceArtifactStore: input.sourceArtifactStore, | 174 | sourceArtifactStore: input.sourceArtifactStore, |
| 148 | runtimeLocalWorkspace: input.runtimeLocalWorkspace, | 175 | runtimeLocalScope: input.runtimeLocalScope, |
| 149 | }); | 176 | }); |
| 150 | let catalog: ToolCatalog | null = null; | 177 | let catalog: ToolCatalog | null = null; |
| 151 | const systemTools = createSystemToolMap({ | 178 | const systemTools = createSystemToolMap({ |
| @@ -180,25 +207,25 @@ export const createWorkspaceToolInvoker = (input: { · 28 unmodified lines | |||
| 180 | args: unknown; | 207 | args: unknown; |
| 181 | context?: Record<string, unknown>; | 208 | context?: Record<string, unknown>; |
| 182 | }) => | 209 | }) => |
| 183 | provideRuntimeLocalWorkspace( | 210 | provideRuntimeLocalScope( |
| 184 | provideWorkspaceStorage( | 211 | provideWorkspaceStorage( |
| 185 | Effect.gen(function* () { | 212 | Effect.gen(function* () { |
| 186 | const catalogTool = yield* loadWorkspaceCatalogToolByPath({ | 213 | const catalogTool = yield* loadWorkspaceCatalogToolByPath({ |
| 187 | workspaceId: input.workspaceId, | 214 | scopeId: input.scopeId, |
| 188 | accountId: input.accountId, | 215 | actorScopeId: input.actorScopeId, |
| 189 | sourceCatalogStore: input.sourceCatalogStore, | 216 | sourceCatalogStore: input.sourceCatalogStore, |
| 190 | path: invocation.path, | 217 | path: invocation.path, |
| 191 | includeSchemas: false, | 218 | includeSchemas: false, |
| 192 | }); | 219 | }); |
| 193 | if (!catalogTool) { | 220 | if (!catalogTool) { |
| 194 | return yield* runtimeEffectError( | 221 | return yield* runtimeEffectError( |
| 195 | "execution/workspace/tool-invoker", | 222 | "execution/scope/tool-invoker", |
| 196 | `Unknown tool path: ${invocation.path}`, | 223 | `Unknown tool path: ${invocation.path}`, |
| 197 | ); | 224 | ); |
| 198 | } | 225 | } |
| 199 | 226 | ||
| 200 | yield* authorizePersistedToolInvocation({ | 227 | yield* authorizePersistedToolInvocation({ |
| 201 | workspaceId: input.workspaceId, | 228 | scopeId: input.scopeId, |
| 202 | tool: catalogTool, | 229 | tool: catalogTool, |
| 203 | args: invocation.args, | 230 | args: invocation.args, |
| 204 | context: invocation.context, | 231 | context: invocation.context, |
| @@ -207,12 +234,12 @@ export const createWorkspaceToolInvoker = (input: { · 2 unmodified lines | |||
| 207 | 234 | ||
| 208 | const auth = yield* input.sourceAuthMaterialService.resolve({ | 235 | const auth = yield* input.sourceAuthMaterialService.resolve({ |
| 209 | source: catalogTool.source, | 236 | source: catalogTool.source, |
| 210 | actorAccountId: input.accountId, | 237 | actorScopeId: input.actorScopeId, |
| 211 | context: toSecretResolutionContext(invocation.context), | 238 | context: toSecretResolutionContext(invocation.context), |
| 212 | }); | 239 | }); |
| 213 | return yield* invokeIrTool({ | 240 | return yield* invokeIrTool({ |
| 214 | workspaceId: input.workspaceId, | 241 | scopeId: input.scopeId, |
| 215 | accountId: input.accountId, | 242 | actorScopeId: input.actorScopeId, |
| 216 | tool: catalogTool, | 243 | tool: catalogTool, |
| 217 | auth, | 244 | auth, |
| 218 | args: invocation.args, | 245 | args: invocation.args, |
| @@ -221,18 +248,18 @@ export const createWorkspaceToolInvoker = (input: { · 2 unmodified lines | |||
| 221 | }); | 248 | }); |
| 222 | }), | 249 | }), |
| 223 | ), | 250 | ), |
| 224 | input.runtimeLocalWorkspace, | 251 | input.runtimeLocalScope, |
| 225 | ); | 252 | ); |
| 226 | 253 | ||
| 227 | return { | 254 | return { |
| 228 | catalog, | 255 | catalog, |
| 229 | toolInvoker: { | 256 | toolInvoker: { |
| 230 | invoke: ({ path, args, context }) => | 257 | invoke: ({ path, args, context }) => |
| 231 | provideRuntimeLocalWorkspace( | 258 | provideRuntimeLocalScope( |
| 232 | authoredToolPaths.has(path) | 259 | authoredToolPaths.has(path) |
| 233 | ? authoredInvoker.invoke({ path, args, context }) | 260 | ? authoredInvoker.invoke({ path, args, context }) |
| 234 | : invokePersistedTool({ path, args, context }), | 261 | : invokePersistedTool({ path, args, context }), |
| 235 | input.runtimeLocalWorkspace, | 262 | input.runtimeLocalScope, |
| 236 | ), | 263 | ), |
| 237 | }, | 264 | }, |
| 238 | }; | 265 | }; |
| @@ -16,12 +16,11 @@ import { · 15 unmodified lines | |||
| 16 | ExecutionIdSchema, | 16 | ExecutionIdSchema, |
| 17 | ExecutionInteractionIdSchema, | 17 | ExecutionInteractionIdSchema, |
| 18 | ExecutionStepIdSchema, | 18 | ExecutionStepIdSchema, |
| 19 | type AccountId, | 19 | type ScopeId, |
| 20 | type Execution, | 20 | type Execution, |
| 21 | type ExecutionEnvelope, | 21 | type ExecutionEnvelope, |
| 22 | type ExecutionId, | 22 | type ExecutionId, |
| 23 | type ExecutionInteraction, | 23 | type ExecutionInteraction, |
| 24 | type WorkspaceId, | ||
| 25 | } from "#schema"; | 24 | } from "#schema"; |
| 26 | import * as Data from "effect/Data"; | 25 | import * as Data from "effect/Data"; |
| 27 | import * as Deferred from "effect/Deferred"; | 26 | import * as Deferred from "effect/Deferred"; |
| @@ -29,16 +28,18 @@ import * as Effect from "effect/Effect"; · 1 unmodified line | |||
| 29 | import * as Option from "effect/Option"; | 28 | import * as Option from "effect/Option"; |
| 30 | import * as Schema from "effect/Schema"; | 29 | import * as Schema from "effect/Schema"; |
| 31 | 30 | ||
| 32 | import { type ResolveExecutionEnvironment } from "./state"; | 31 | import { |
| 32 | type ResolveExecutionEnvironment, | ||
| 33 | } from "./state"; | ||
| 33 | import { | 34 | import { |
| 34 | LiveExecutionManagerService, | 35 | LiveExecutionManagerService, |
| 35 | sanitizePersistedElicitationResponse, | 36 | sanitizePersistedElicitationResponse, |
| 36 | type LiveExecutionManager, | 37 | type LiveExecutionManager, |
| 37 | } from "./live"; | 38 | } from "./live"; |
| 38 | import { | 39 | import { |
| 39 | getRuntimeLocalWorkspaceOption, | 40 | getRuntimeLocalScopeOption, |
| 40 | provideOptionalRuntimeLocalWorkspace, | 41 | provideOptionalRuntimeLocalScope, |
| 41 | } from "../workspace/runtime-context"; | 42 | } from "../scope/runtime-context"; |
| 42 | import { | 43 | import { |
| 43 | asOperationErrors, | 44 | asOperationErrors, |
| 44 | operationErrors, | 45 | operationErrors, |
| @@ -48,8 +49,12 @@ import { · 3 unmodified lines | |||
| 48 | ExecutorStateStore, | 49 | ExecutorStateStore, |
| 49 | type ExecutorStateStoreShape, | 50 | type ExecutorStateStoreShape, |
| 50 | } from "../executor-state-store"; | 51 | } from "../executor-state-store"; |
| 51 | import { RuntimeExecutionResolverService } from "./workspace/environment"; | 52 | import { |
| 52 | import { runtimeEffectError } from "../effect-errors"; | 53 | RuntimeExecutionResolverService, |
| 54 | } from "./scope/environment"; | ||
| 55 | import { | ||
| 56 | runtimeEffectError, | ||
| 57 | } from "../effect-errors"; | ||
| 53 | 58 | ||
| 54 | const executionOps = { | 59 | const executionOps = { |
| 55 | create: operationErrors("executions.create"), | 60 | create: operationErrors("executions.create"), |
| @@ -246,7 +251,7 @@ const verifyStoredStepMatches = (input: { · 190 unmodified lines | |||
| 246 | const fetchExecution = ( | 251 | const fetchExecution = ( |
| 247 | store: ExecutorStateStoreShape, | 252 | store: ExecutorStateStoreShape, |
| 248 | input: { | 253 | input: { |
| 249 | workspaceId: Execution["workspaceId"]; | 254 | scopeId: Execution["scopeId"]; |
| 250 | executionId: Execution["id"]; | 255 | executionId: Execution["id"]; |
| 251 | operation: OperationErrorsLike; | 256 | operation: OperationErrorsLike; |
| 252 | }, | 257 | }, |
| @@ -254,13 +259,13 @@ const fetchExecution = ( · 1 unmodified line | |||
| 254 | Effect.gen(function* () { | 259 | Effect.gen(function* () { |
| 255 | const errors = asOperationErrors(input.operation); | 260 | const errors = asOperationErrors(input.operation); |
| 256 | const existing = yield* errors.mapStorage( | 261 | const existing = yield* errors.mapStorage( |
| 257 | store.executions.getByWorkspaceAndId(input.workspaceId, input.executionId), | 262 | store.executions.getByScopeAndId(input.scopeId, input.executionId), |
| 258 | ); | 263 | ); |
| 259 | 264 | ||
| 260 | if (Option.isNone(existing)) { | 265 | if (Option.isNone(existing)) { |
| 261 | return yield* errors.notFound( | 266 | return yield* errors.notFound( |
| 262 | "Execution not found", | 267 | "Execution not found", |
| 263 | `workspaceId=${input.workspaceId} executionId=${input.executionId}`, | 268 | `scopeId=${input.scopeId} executionId=${input.executionId}`, |
| 264 | ); | 269 | ); |
| 265 | } | 270 | } |
| 266 | 271 | ||
| @@ -270,7 +275,7 @@ const fetchExecution = ( · 3 unmodified lines | |||
| 270 | const fetchExecutionEnvelope = ( | 275 | const fetchExecutionEnvelope = ( |
| 271 | store: ExecutorStateStoreShape, | 276 | store: ExecutorStateStoreShape, |
| 272 | input: { | 277 | input: { |
| 273 | workspaceId: Execution["workspaceId"]; | 278 | scopeId: Execution["scopeId"]; |
| 274 | executionId: Execution["id"]; | 279 | executionId: Execution["id"]; |
| 275 | operation: OperationErrorsLike; | 280 | operation: OperationErrorsLike; |
| 276 | }, | 281 | }, |
| @@ -291,7 +296,7 @@ const fetchExecutionEnvelope = ( · 14 unmodified lines | |||
| 291 | const waitForExecutionEnvelopeToSettle = ( | 296 | const waitForExecutionEnvelopeToSettle = ( |
| 292 | store: ExecutorStateStoreShape, | 297 | store: ExecutorStateStoreShape, |
| 293 | input: { | 298 | input: { |
| 294 | workspaceId: Execution["workspaceId"]; | 299 | scopeId: Execution["scopeId"]; |
| 295 | executionId: Execution["id"]; | 300 | executionId: Execution["id"]; |
| 296 | operation: OperationErrorsLike; | 301 | operation: OperationErrorsLike; |
| 297 | previousPendingInteractionId: ExecutionInteraction["id"] | null; | 302 | previousPendingInteractionId: ExecutionInteraction["id"] | null; |
| @@ -658,8 +663,8 @@ const runExecutionAttemptWithDependencies = ( · 360 unmodified lines | |||
| 658 | interactionMode: InteractionMode, | 663 | interactionMode: InteractionMode, |
| 659 | ) => | 664 | ) => |
| 660 | executionResolver({ | 665 | executionResolver({ |
| 661 | workspaceId: execution.workspaceId, | 666 | scopeId: execution.scopeId, |
| 662 | accountId: execution.createdByAccountId, | 667 | actorScopeId: execution.createdByScopeId, |
| 663 | executionId: execution.id, | 668 | executionId: execution.id, |
| 664 | onElicitation: createHybridOnElicitation({ | 669 | onElicitation: createHybridOnElicitation({ |
| 665 | executorState: store, | 670 | executorState: store, |
| @@ -710,7 +715,7 @@ const forkExecutionAttemptWithDependencies = ( · 44 unmodified lines | |||
| 710 | interactionMode: InteractionMode, | 715 | interactionMode: InteractionMode, |
| 711 | ) => | 716 | ) => |
| 712 | Effect.gen(function* () { | 717 | Effect.gen(function* () { |
| 713 | const runtimeLocalWorkspace = yield* getRuntimeLocalWorkspaceOption(); | 718 | const runtimeLocalScope = yield* getRuntimeLocalScopeOption(); |
| 714 | 719 | ||
| 715 | yield* Effect.sync(() => { | 720 | yield* Effect.sync(() => { |
| 716 | const effect = runExecutionAttemptWithDependencies( | 721 | const effect = runExecutionAttemptWithDependencies( |
| @@ -722,7 +727,7 @@ const forkExecutionAttemptWithDependencies = ( · 5 unmodified lines | |||
| 722 | ); | 727 | ); |
| 723 | 728 | ||
| 724 | Effect.runFork( | 729 | Effect.runFork( |
| 725 | provideOptionalRuntimeLocalWorkspace(effect, runtimeLocalWorkspace), | 730 | provideOptionalRuntimeLocalScope(effect, runtimeLocalScope), |
| 726 | ); | 731 | ); |
| 727 | }); | 732 | }); |
| 728 | }); | 733 | }); |
| @@ -808,9 +813,9 @@ const createExecutionWithDependencies = ( · 79 unmodified lines | |||
| 808 | executionResolver: ResolveExecutionEnvironment, | 813 | executionResolver: ResolveExecutionEnvironment, |
| 809 | liveExecutionManager: LiveExecutionManager, | 814 | liveExecutionManager: LiveExecutionManager, |
| 810 | input: { | 815 | input: { |
| 811 | workspaceId: WorkspaceId; | 816 | scopeId: ScopeId; |
| 812 | payload: CreateExecutionPayload; | 817 | payload: CreateExecutionPayload; |
| 813 | createdByAccountId: AccountId; | 818 | createdByScopeId: ScopeId; |
| 814 | }, | 819 | }, |
| 815 | ) => | 820 | ) => |
| 816 | Effect.gen(function* () { | 821 | Effect.gen(function* () { |
| @@ -818,8 +823,8 @@ const createExecutionWithDependencies = ( · 1 unmodified line | |||
| 818 | const now = Date.now(); | 823 | const now = Date.now(); |
| 819 | const execution: Execution = { | 824 | const execution: Execution = { |
| 820 | id: ExecutionIdSchema.make(`exec_${crypto.randomUUID()}`), | 825 | id: ExecutionIdSchema.make(`exec_${crypto.randomUUID()}`), |
| 821 | workspaceId: input.workspaceId, | 826 | scopeId: input.scopeId, |
| 822 | createdByAccountId: input.createdByAccountId, | 827 | createdByScopeId: input.createdByScopeId, |
| 823 | status: "pending", | 828 | status: "pending", |
| 824 | code, | 829 | code, |
| 825 | resultJson: null, | 830 | resultJson: null, |
| @@ -863,16 +868,16 @@ const createExecutionWithDependencies = ( · 37 unmodified lines | |||
| 863 | yield* Deferred.await(nextState); | 868 | yield* Deferred.await(nextState); |
| 864 | 869 | ||
| 865 | return yield* fetchExecutionEnvelope(store, { | 870 | return yield* fetchExecutionEnvelope(store, { |
| 866 | workspaceId: input.workspaceId, | 871 | scopeId: input.scopeId, |
| 867 | executionId: execution.id, | 872 | executionId: execution.id, |
| 868 | operation: executionOps.create, | 873 | operation: executionOps.create, |
| 869 | }); | 874 | }); |
| 870 | }); | 875 | }); |
| 871 | 876 | ||
| 872 | export const createExecution = (input: { | 877 | export const createExecution = (input: { |
| 873 | workspaceId: WorkspaceId; | 878 | scopeId: ScopeId; |
| 874 | payload: CreateExecutionPayload; | 879 | payload: CreateExecutionPayload; |
| 875 | createdByAccountId: AccountId; | 880 | createdByScopeId: ScopeId; |
| 876 | }) => | 881 | }) => |
| 877 | Effect.gen(function* () { | 882 | Effect.gen(function* () { |
| 878 | const store = yield* ExecutorStateStore; | 883 | const store = yield* ExecutorStateStore; |
| @@ -888,12 +893,12 @@ export const createExecution = (input: { · 9 unmodified lines | |||
| 888 | }); | 893 | }); |
| 889 | 894 | ||
| 890 | export const getExecution = (input: { | 895 | export const getExecution = (input: { |
| 891 | workspaceId: WorkspaceId; | 896 | scopeId: ScopeId; |
| 892 | executionId: ExecutionId; | 897 | executionId: ExecutionId; |
| 893 | }) => | 898 | }) => |
| 894 | Effect.flatMap(ExecutorStateStore, (store) => | 899 | Effect.flatMap(ExecutorStateStore, (store) => |
| 895 | fetchExecutionEnvelope(store, { | 900 | fetchExecutionEnvelope(store, { |
| 896 | workspaceId: input.workspaceId, | 901 | scopeId: input.scopeId, |
| 897 | executionId: input.executionId, | 902 | executionId: input.executionId, |
| 898 | operation: executionOps.get, | 903 | operation: executionOps.get, |
| 899 | }) | 904 | }) |
| @@ -921,10 +926,10 @@ export const submitExecutionInteractionResponse = (input: { · 21 unmodified lines | |||
| 921 | }); | 926 | }); |
| 922 | 927 | ||
| 923 | export const resumeExecution = (input: { | 928 | export const resumeExecution = (input: { |
| 924 | workspaceId: WorkspaceId; | 929 | scopeId: ScopeId; |
| 925 | executionId: ExecutionId; | 930 | executionId: ExecutionId; |
| 926 | payload: ResumeExecutionPayload; | 931 | payload: ResumeExecutionPayload; |
| 927 | resumedByAccountId: AccountId; | 932 | resumedByScopeId: ScopeId; |
| 928 | }) => | 933 | }) => |
| 929 | Effect.gen(function* () { | 934 | Effect.gen(function* () { |
| 930 | const store = yield* ExecutorStateStore; | 935 | const store = yield* ExecutorStateStore; |
| @@ -932,7 +937,7 @@ export const resumeExecution = (input: { · 1 unmodified line | |||
| 932 | const liveExecutionManager = yield* LiveExecutionManagerService; | 937 | const liveExecutionManager = yield* LiveExecutionManagerService; |
| 933 | 938 | ||
| 934 | const existing = yield* fetchExecutionEnvelope(store, { | 939 | const existing = yield* fetchExecutionEnvelope(store, { |
| 935 | workspaceId: input.workspaceId, | 940 | scopeId: input.scopeId, |
| 936 | executionId: input.executionId, | 941 | executionId: input.executionId, |
| 937 | operation: "executions.resume", | 942 | operation: "executions.resume", |
| 938 | }); | 943 | }); |
| @@ -1002,7 +1007,7 @@ export const resumeExecution = (input: { · 63 unmodified lines | |||
| 1002 | } | 1007 | } |
| 1003 | 1008 | ||
| 1004 | return yield* waitForExecutionEnvelopeToSettle(store, { | 1009 | return yield* waitForExecutionEnvelopeToSettle(store, { |
| 1005 | workspaceId: input.workspaceId, | 1010 | scopeId: input.scopeId, |
| 1006 | executionId: input.executionId, | 1011 | executionId: input.executionId, |
| 1007 | operation: executionOps.resume, | 1012 | operation: executionOps.resume, |
| 1008 | previousPendingInteractionId: existing.pendingInteraction?.id ?? null, | 1013 | previousPendingInteractionId: existing.pendingInteraction?.id ?? null, |
| @@ -4,7 +4,10 @@ import type { · 3 unmodified lines | |||
| 4 | ToolCatalog, | 4 | ToolCatalog, |
| 5 | ToolInvoker, | 5 | ToolInvoker, |
| 6 | } from "@executor/codemode-core"; | 6 | } from "@executor/codemode-core"; |
| 7 | import type { AccountId, ExecutionId, WorkspaceId } from "#schema"; | 7 | import type { |
| 8 | ScopeId, | ||
| 9 | ExecutionId, | ||
| 10 | } from "#schema"; | ||
| 8 | import * as Data from "effect/Data"; | 11 | import * as Data from "effect/Data"; |
| 9 | import type * as Effect from "effect/Effect"; | 12 | import type * as Effect from "effect/Effect"; |
| 10 | 13 | ||
| @@ -15,8 +18,8 @@ export type ExecutionEnvironment = { · 4 unmodified lines | |||
| 15 | }; | 18 | }; |
| 16 | 19 | ||
| 17 | export type ResolveExecutionEnvironment = (input: { | 20 | export type ResolveExecutionEnvironment = (input: { |
| 18 | workspaceId: WorkspaceId; | 21 | scopeId: ScopeId; |
| 19 | accountId: AccountId; | 22 | actorScopeId: ScopeId; |
| 20 | executionId: ExecutionId; | 23 | executionId: ExecutionId; |
| 21 | onElicitation?: OnElicitation; | 24 | onElicitation?: OnElicitation; |
| 22 | }) => Effect.Effect<ExecutionEnvironment, unknown>; | 25 | }) => Effect.Effect<ExecutionEnvironment, unknown>; |
| @@ -3,7 +3,9 @@ import { · 2 unmodified lines | |||
| 3 | HttpApiClient, | 3 | HttpApiClient, |
| 4 | HttpServer, | 4 | HttpServer, |
| 5 | } from "@effect/platform"; | 5 | } from "@effect/platform"; |
| 6 | import { NodeHttpServer } from "@effect/platform-node"; | 6 | import { |
| 7 | NodeHttpServer, | ||
| 8 | } from "@effect/platform-node"; | ||
| 7 | import { | 9 | import { |
| 8 | ExecutorApi, | 10 | ExecutorApi, |
| 9 | createExecutorApiLayer, | 11 | createExecutorApiLayer, |
| @@ -93,7 +95,7 @@ type ExecutorApiClient = Effect.Effect.Success< · 83 unmodified lines | |||
| 93 | export const withExecutorApiClient = <A, E>( | 95 | export const withExecutorApiClient = <A, E>( |
| 94 | input: { | 96 | input: { |
| 95 | runtime: ExecutorRuntime; | 97 | runtime: ExecutorRuntime; |
| 96 | accountId?: string; | 98 | actorScopeId?: string; |
| 97 | }, | 99 | }, |
| 98 | f: (client: ExecutorApiClient) => Effect.Effect<A, E, never>, | 100 | f: (client: ExecutorApiClient) => Effect.Effect<A, E, never>, |
| 99 | ): Effect.Effect<A, E, never> => | 101 | ): Effect.Effect<A, E, never> => |
| @@ -1,12 +0,0 @@ | |||
| 1 | import * as Effect from "effect/Effect"; | ||
| 2 | |||
| 3 | import { | ||
| 4 | provideOptionalRuntimeLocalWorkspace, | ||
| 5 | type RuntimeLocalWorkspaceState, | ||
| 6 | } from "../../workspace/runtime-context"; | ||
| 7 | |||
| 8 | export const provideRuntimeLocalWorkspace = <A, E, R>( | ||
| 9 | effect: Effect.Effect<A, E, R>, | ||
| 10 | runtimeLocalWorkspace: RuntimeLocalWorkspaceState | null, | ||
| 11 | ): Effect.Effect<A, E, R> => | ||
| 12 | provideOptionalRuntimeLocalWorkspace(effect, runtimeLocalWorkspace); | ||
| @@ -1,14 +1,35 @@ | |||
| 1 | import { createServer } from "node:http"; | 1 | import { |
| 2 | import { join } from "node:path"; | 2 | createServer, |
| 3 | } from "node:http"; | ||
| 4 | import { | ||
| 5 | join, | ||
| 6 | } from "node:path"; | ||
| 3 | 7 | ||
| 4 | import { FileSystem } from "@effect/platform"; | 8 | import { |
| 5 | import { NodeFileSystem } from "@effect/platform-node"; | 9 | FileSystem, |
| 6 | import { describe, expect, it } from "@effect/vitest"; | 10 | HttpApi, |
| 7 | import { assertTrue } from "@effect/vitest/utils"; | 11 | HttpApiEndpoint, |
| 12 | HttpApiGroup, | ||
| 13 | HttpApiSchema, | ||
| 14 | HttpApiBuilder, | ||
| 15 | } from "@effect/platform"; | ||
| 16 | import { | ||
| 17 | NodeFileSystem, | ||
| 18 | } from "@effect/platform-node"; | ||
| 19 | import { | ||
| 20 | describe, | ||
| 21 | expect, | ||
| 22 | it, | ||
| 23 | } from "@effect/vitest"; | ||
| 24 | import { | ||
| 25 | assertTrue, | ||
| 26 | } from "@effect/vitest/utils"; | ||
| 8 | import * as Either from "effect/Either"; | 27 | import * as Either from "effect/Either"; |
| 9 | import * as Effect from "effect/Effect"; | 28 | import * as Effect from "effect/Effect"; |
| 10 | import * as Fiber from "effect/Fiber"; | 29 | import * as Fiber from "effect/Fiber"; |
| 30 | import * as Layer from "effect/Layer"; | ||
| 11 | import * as Option from "effect/Option"; | 31 | import * as Option from "effect/Option"; |
| 32 | import * as Schema from "effect/Schema"; | ||
| 12 | 33 | ||
| 13 | import { | 34 | import { |
| 14 | ExecutionIdSchema, | 35 | ExecutionIdSchema, |
| @@ -18,12 +39,23 @@ import { · 3 unmodified lines | |||
| 18 | SecretMaterialIdSchema, | 39 | SecretMaterialIdSchema, |
| 19 | SourceAuthSessionIdSchema, | 40 | SourceAuthSessionIdSchema, |
| 20 | SourceIdSchema, | 41 | SourceIdSchema, |
| 21 | WorkspaceOauthClientIdSchema, | 42 | ScopeOauthClientIdSchema, |
| 22 | } from "#schema"; | 43 | } from "#schema"; |
| 23 | import type { ToolPath } from "@executor/codemode-core"; | 44 | import type { |
| 24 | import { createCatalogImportMetadata } from "@executor/source-core"; | 45 | ToolPath, |
| 25 | import { createGraphqlCatalogFragment } from "@executor/source-graphql"; | 46 | } from "@executor/codemode-core"; |
| 26 | import { createWorkspaceExecutorAdminToolMap } from "../../../internal/src/index"; | 47 | import { |
| 48 | makeOpenApiTestServer, | ||
| 49 | } from "@executor/effect-test-utils"; | ||
| 50 | import { | ||
| 51 | createCatalogImportMetadata, | ||
| 52 | } from "@executor/source-core"; | ||
| 53 | import { | ||
| 54 | createGraphqlCatalogFragment, | ||
| 55 | } from "@executor/source-graphql"; | ||
| 56 | import { | ||
| 57 | createWorkspaceExecutorAdminToolMap, | ||
| 58 | } from "../../../internal/src/index"; | ||
| 27 | 59 | ||
| 28 | import { | 60 | import { |
| 29 | type ExecutorRuntime, | 61 | type ExecutorRuntime, |
| @@ -31,14 +63,22 @@ import { · 1 unmodified line | |||
| 31 | provideExecutorRuntime, | 63 | provideExecutorRuntime, |
| 32 | RuntimeExecutionResolverService, | 64 | RuntimeExecutionResolverService, |
| 33 | } from "./index"; | 65 | } from "./index"; |
| 34 | import { createSourceFromPayload } from "./sources/source-definitions"; | 66 | import { |
| 35 | import { decodeSourceCredentialSelectionContent } from "./sources/source-credential-interactions"; | 67 | createSourceFromPayload, |
| 36 | import { persistSource } from "./sources/source-store"; | 68 | } from "./sources/source-definitions"; |
| 69 | import { | ||
| 70 | decodeSourceCredentialSelectionContent, | ||
| 71 | } from "./sources/source-credential-interactions"; | ||
| 72 | import { | ||
| 73 | persistSource, | ||
| 74 | } from "./sources/source-store"; | ||
| 37 | import { | 75 | import { |
| 38 | withExecutorApiClient, | 76 | withExecutorApiClient, |
| 39 | withExecutorApiRequestHandler, | 77 | withExecutorApiRequestHandler, |
| 40 | } from "./execution/test-http-client"; | 78 | } from "./execution/test-http-client"; |
| 41 | import { runtimeEffectError } from "./effect-errors"; | 79 | import { |
| 80 | runtimeEffectError, | ||
| 81 | } from "./effect-errors"; | ||
| 42 | import { | 82 | import { |
| 43 | buildLocalSourceArtifact, | 83 | buildLocalSourceArtifact, |
| 44 | createLocalExecutorRuntime as createExecutorRuntime, | 84 | createLocalExecutorRuntime as createExecutorRuntime, |
| @@ -57,15 +97,15 @@ import { · 12 unmodified lines | |||
| 57 | 97 | ||
| 58 | const makeRuntime = Effect.gen(function* () { | 98 | const makeRuntime = Effect.gen(function* () { |
| 59 | const fs = yield* FileSystem.FileSystem; | 99 | const fs = yield* FileSystem.FileSystem; |
| 60 | const workspaceRoot = yield* fs.makeTempDirectoryScoped({ | 100 | const scopeRoot = yield* fs.makeTempDirectoryScoped({ |
| 61 | prefix: "executor-runtime-", | 101 | prefix: "executor-runtime-", |
| 62 | }); | 102 | }); |
| 63 | const homeConfigPath = join(workspaceRoot, ".executor-home.jsonc"); | 103 | const homeConfigPath = join(scopeRoot, ".executor-home.jsonc"); |
| 64 | const homeStateDirectory = join(workspaceRoot, ".executor-home-state"); | 104 | const homeStateDirectory = join(scopeRoot, ".executor-home-state"); |
| 65 | 105 | ||
| 66 | return yield* Effect.acquireRelease( | 106 | return yield* Effect.acquireRelease( |
| 67 | createExecutorRuntime({ | 107 | createExecutorRuntime({ |
| 68 | workspaceRoot, | 108 | workspaceRoot: scopeRoot, |
| 69 | homeConfigPath, | 109 | homeConfigPath, |
| 70 | homeStateDirectory, | 110 | homeStateDirectory, |
| 71 | createInternalToolMap: createWorkspaceExecutorAdminToolMap, | 111 | createInternalToolMap: createWorkspaceExecutorAdminToolMap, |
| @@ -74,11 +114,19 @@ const makeRuntime = Effect.gen(function* () { · 2 unmodified lines | |||
| 74 | ); | 114 | ); |
| 75 | }).pipe(Effect.provide(NodeFileSystem.layer)); | 115 | }).pipe(Effect.provide(NodeFileSystem.layer)); |
| 76 | 116 | ||
| 77 | type OpenApiSpecServer = { | 117 | const ownerParam = HttpApiSchema.param("owner", Schema.String); |
| 78 | baseUrl: string; | 118 | const repoParam = HttpApiSchema.param("repo", Schema.String); |
| 79 | specUrl: string; | 119 | |
| 80 | close: () => Promise<void>; | 120 | class RuntimeTestReposApi extends HttpApiGroup.make("repos") |
| 81 | }; | 121 | .add( |
| 122 | HttpApiEndpoint.get("getRepo")`/repos/${ownerParam}/${repoParam}` | ||
| 123 | .addSuccess(Schema.Unknown), | ||
| 124 | ) | ||
| 125 | {} | ||
| 126 | |||
| 127 | class RuntimeTestOpenApi extends HttpApi.make("runtimeTest").add( | ||
| 128 | RuntimeTestReposApi, | ||
| 129 | ) {} | ||
| 82 | 130 | ||
| 83 | type GoogleWorkspaceTestServer = { | 131 | type GoogleWorkspaceTestServer = { |
| 84 | baseUrl: string; | 132 | baseUrl: string; |
| @@ -99,74 +147,26 @@ type GoogleWorkspaceTestServer = { · 14 unmodified lines | |||
| 99 | close: () => Promise<void>; | 147 | close: () => Promise<void>; |
| 100 | }; | 148 | }; |
| 101 | 149 | ||
| 102 | const makeOpenApiSpecServer = Effect.acquireRelease( | 150 | const runtimeTestOpenApiLive = HttpApiBuilder.group( |
| 103 | Effect.promise<OpenApiSpecServer>( | 151 | RuntimeTestOpenApi, |
| 104 | () => | 152 | "repos", |
| 105 | new Promise<OpenApiSpecServer>((resolve, reject) => { | 153 | (handlers) => |
| 106 | const openApiDocument = JSON.stringify({ | 154 | handlers.handle("getRepo", ({ path }) => |
| 107 | openapi: "3.0.3", | 155 | Effect.succeed({ |
| 108 | info: { | 156 | full_name: `${path.owner}/${path.repo}`, |
| 109 | title: "GitHub Test API", | 157 | private: false, |
| 110 | version: "1.0.0", | ||
| 111 | }, | ||
| 112 | paths: { | ||
| 113 | "/repos/{owner}/{repo}": { | ||
| 114 | get: { | ||
| 115 | operationId: "repos/get-repo", | ||
| 116 | tags: ["repos"], | ||
| 117 | summary: "Get a repository", | ||
| 118 | responses: { | ||
| 119 | 200: { | ||
| 120 | description: "ok", | ||
| 121 | }, | ||
| 122 | }, | ||
| 123 | }, | ||
| 124 | }, | ||
| 125 | }, | ||
| 126 | }); | ||
| 127 | |||
| 128 | const server = createServer((request, response) => { | ||
| 129 | if (request.url !== "/openapi.json") { | ||
| 130 | response.statusCode = 404; | ||
| 131 | response.end(); | ||
| 132 | return; | ||
| 133 | } | ||
| 134 | |||
| 135 | response.statusCode = 200; | ||
| 136 | response.setHeader("content-type", "application/json"); | ||
| 137 | response.end(openApiDocument); | ||
| 138 | }); | ||
| 139 | |||
| 140 | server.once("error", reject); | ||
| 141 | server.listen(0, "127.0.0.1", () => { | ||
| 142 | const address = server.address(); | ||
| 143 | if (!address || typeof address === "string") { | ||
| 144 | reject(new Error("Failed to bind OpenAPI runtime test server")); | ||
| 145 | return; | ||
| 146 | } | ||
| 147 | |||
| 148 | const baseUrl = `http://127.0.0.1:${address.port}`; | ||
| 149 | resolve({ | ||
| 150 | baseUrl, | ||
| 151 | specUrl: `${baseUrl}/openapi.json`, | ||
| 152 | close: () => | ||
| 153 | new Promise<void>((closeResolve, closeReject) => { | ||
| 154 | server.close((error) => { | ||
| 155 | if (error) { | ||
| 156 | closeReject(error); | ||
| 157 | return; | ||
| 158 | } | ||
| 159 | |||
| 160 | closeResolve(); | ||
| 161 | }); | ||
| 162 | }), | ||
| 163 | }); | ||
| 164 | }); | ||
| 165 | }), | 158 | }), |
| 166 | ), | 159 | ), |
| 167 | (server) => Effect.promise(() => server.close()).pipe(Effect.orDie), | ||
| 168 | ); | 160 | ); |
| 169 | 161 | ||
| 162 | const runtimeTestOpenApiLayer = HttpApiBuilder.api(RuntimeTestOpenApi).pipe( | ||
| 163 | Layer.provide(runtimeTestOpenApiLive), | ||
| 164 | ); | ||
| 165 | |||
| 166 | const makeOpenApiSpecServer = makeOpenApiTestServer({ | ||
| 167 | apiLayer: runtimeTestOpenApiLayer, | ||
| 168 | }); | ||
| 169 | |||
| 170 | const makeGoogleWorkspaceTestServer = Effect.acquireRelease( | 170 | const makeGoogleWorkspaceTestServer = Effect.acquireRelease( |
| 171 | Effect.promise<GoogleWorkspaceTestServer>( | 171 | Effect.promise<GoogleWorkspaceTestServer>( |
| 172 | () => | 172 | () => |
| @@ -379,7 +379,7 @@ const createPersistedGoogleSource = (input: { · 206 unmodified lines | |||
| 379 | Effect.gen(function* () { | 379 | Effect.gen(function* () { |
| 380 | const installation = input.runtime.localInstallation; | 380 | const installation = input.runtime.localInstallation; |
| 381 | const source = yield* createSourceFromPayload({ | 381 | const source = yield* createSourceFromPayload({ |
| 382 | workspaceId: installation.workspaceId, | 382 | scopeId: installation.scopeId, |
| 383 | sourceId: SourceIdSchema.make(`src_${crypto.randomUUID()}`), | 383 | sourceId: SourceIdSchema.make(`src_${crypto.randomUUID()}`), |
| 384 | payload: { | 384 | payload: { |
| 385 | name: input.name, | 385 | name: input.name, |
| @@ -402,7 +402,7 @@ const createPersistedGoogleSource = (input: { · 16 unmodified lines | |||
| 402 | }); | 402 | }); |
| 403 | 403 | ||
| 404 | return yield* persistSource(input.runtime.storage.executorState, source, { | 404 | return yield* persistSource(input.runtime.storage.executorState, source, { |
| 405 | actorAccountId: installation.accountId, | 405 | actorScopeId: installation.actorScopeId, |
| 406 | }).pipe((effect) => provideExecutorRuntime(effect, input.runtime)); | 406 | }).pipe((effect) => provideExecutorRuntime(effect, input.runtime)); |
| 407 | }); | 407 | }); |
| 408 | 408 | ||
| @@ -430,8 +430,8 @@ const invokeWorkspaceTool = <A>(input: { · 21 unmodified lines | |||
| 430 | const installation = input.runtime.localInstallation; | 430 | const installation = input.runtime.localInstallation; |
| 431 | const resolveEnvironment = yield* RuntimeExecutionResolverService; | 431 | const resolveEnvironment = yield* RuntimeExecutionResolverService; |
| 432 | const environment = yield* resolveEnvironment({ | 432 | const environment = yield* resolveEnvironment({ |
| 433 | workspaceId: installation.workspaceId, | 433 | scopeId: installation.scopeId, |
| 434 | accountId: installation.accountId, | 434 | actorScopeId: installation.actorScopeId, |
| 435 | executionId: ExecutionIdSchema.make(`exec_tool_${crypto.randomUUID()}`), | 435 | executionId: ExecutionIdSchema.make(`exec_tool_${crypto.randomUUID()}`), |
| 436 | }); | 436 | }); |
| 437 | 437 | ||
| @@ -449,14 +449,14 @@ describe("executor-runtime", () => { · 11 unmodified lines | |||
| 449 | () => | 449 | () => |
| 450 | Effect.gen(function* () { | 450 | Effect.gen(function* () { |
| 451 | const fs = yield* FileSystem.FileSystem; | 451 | const fs = yield* FileSystem.FileSystem; |
| 452 | const workspaceRoot = yield* fs.makeTempDirectoryScoped({ | 452 | const scopeRoot = yield* fs.makeTempDirectoryScoped({ |
| 453 | prefix: "executor-local-config-runtime-", | 453 | prefix: "executor-local-config-runtime-", |
| 454 | }); | 454 | }); |
| 455 | const homeConfigPath = join(workspaceRoot, ".executor-home.jsonc"); | 455 | const homeConfigPath = join(scopeRoot, ".executor-home.jsonc"); |
| 456 | const homeStateDirectory = join(workspaceRoot, ".executor-home-state"); | 456 | const homeStateDirectory = join(scopeRoot, ".executor-home-state"); |
| 457 | const runtime = yield* Effect.acquireRelease( | 457 | const runtime = yield* Effect.acquireRelease( |
| 458 | createExecutorRuntime({ | 458 | createExecutorRuntime({ |
| 459 | workspaceRoot, | 459 | workspaceRoot: scopeRoot, |
| 460 | homeConfigPath, | 460 | homeConfigPath, |
| 461 | homeStateDirectory, | 461 | homeStateDirectory, |
| 462 | }), | 462 | }), |
| @@ -467,10 +467,10 @@ describe("executor-runtime", () => { · 4 unmodified lines | |||
| 467 | const installation = runtime.localInstallation; | 467 | const installation = runtime.localInstallation; |
| 468 | 468 | ||
| 469 | const createdSource = yield* withExecutorApiClient( | 469 | const createdSource = yield* withExecutorApiClient( |
| 470 | { runtime, accountId: installation.accountId }, | 470 | { runtime, actorScopeId: installation.actorScopeId }, |
| 471 | (client) => | 471 | (client) => |
| 472 | client.sources.create({ | 472 | client.sources.create({ |
| 473 | path: { workspaceId: installation.workspaceId }, | 473 | path: { workspaceId: installation.scopeId }, |
| 474 | payload: { | 474 | payload: { |
| 475 | name: "GitHub", | 475 | name: "GitHub", |
| 476 | kind: "openapi", | 476 | kind: "openapi", |
| @@ -485,7 +485,7 @@ describe("executor-runtime", () => { · 8 unmodified lines | |||
| 485 | }), | 485 | }), |
| 486 | ); | 486 | ); |
| 487 | 487 | ||
| 488 | const configPath = join(workspaceRoot, ".executor", "executor.jsonc"); | 488 | const configPath = join(scopeRoot, ".executor", "executor.jsonc"); |
| 489 | const createdConfig = JSON.parse( | 489 | const createdConfig = JSON.parse( |
| 490 | yield* fs.readFileString(configPath, "utf8"), | 490 | yield* fs.readFileString(configPath, "utf8"), |
| 491 | ) as { | 491 | ) as { |
| @@ -500,11 +500,11 @@ describe("executor-runtime", () => { · 8 unmodified lines | |||
| 500 | ); | 500 | ); |
| 501 | 501 | ||
| 502 | const removed = yield* withExecutorApiClient( | 502 | const removed = yield* withExecutorApiClient( |
| 503 | { runtime, accountId: installation.accountId }, | 503 | { runtime, actorScopeId: installation.actorScopeId }, |
| 504 | (client) => | 504 | (client) => |
| 505 | client.sources.remove({ | 505 | client.sources.remove({ |
| 506 | path: { | 506 | path: { |
| 507 | workspaceId: installation.workspaceId, | 507 | workspaceId: installation.scopeId, |
| 508 | sourceId: createdSource.id, | 508 | sourceId: createdSource.id, |
| 509 | }, | 509 | }, |
| 510 | }), | 510 | }), |
| @@ -615,11 +615,11 @@ describe("executor-runtime", () => { · 104 unmodified lines | |||
| 615 | const openApiServer = yield* makeOpenApiSpecServer; | 615 | const openApiServer = yield* makeOpenApiSpecServer; |
| 616 | const installation = runtime.localInstallation; | 616 | const installation = runtime.localInstallation; |
| 617 | const createdSource = yield* withExecutorApiClient( | 617 | const createdSource = yield* withExecutorApiClient( |
| 618 | { runtime, accountId: installation.accountId }, | 618 | { runtime, actorScopeId: installation.actorScopeId }, |
| 619 | (client) => | 619 | (client) => |
| 620 | client.sources.create({ | 620 | client.sources.create({ |
| 621 | path: { | 621 | path: { |
| 622 | workspaceId: installation.workspaceId, | 622 | workspaceId: installation.scopeId, |
| 623 | }, | 623 | }, |
| 624 | payload: { | 624 | payload: { |
| 625 | name: "GitHub", | 625 | name: "GitHub", |
| @@ -640,15 +640,15 @@ describe("executor-runtime", () => { · 14 unmodified lines | |||
| 640 | ); | 640 | ); |
| 641 | 641 | ||
| 642 | const localInstallation = yield* invokeWorkspaceTool<{ | 642 | const localInstallation = yield* invokeWorkspaceTool<{ |
| 643 | workspaceId: string; | 643 | scopeId: string; |
| 644 | accountId: string; | 644 | actorScopeId: string; |
| 645 | }>({ | 645 | }>({ |
| 646 | runtime, | 646 | runtime, |
| 647 | path: "executor.local.installation.get" as ToolPath, | 647 | path: "executor.local.installation.get" as ToolPath, |
| 648 | args: {}, | 648 | args: {}, |
| 649 | }); | 649 | }); |
| 650 | expect(localInstallation.workspaceId).toBe(installation.workspaceId); | 650 | expect(localInstallation.scopeId).toBe(installation.scopeId); |
| 651 | expect(localInstallation.accountId).toBe(installation.accountId); | 651 | expect(localInstallation.actorScopeId).toBe(installation.actorScopeId); |
| 652 | 652 | ||
| 653 | const localConfig = yield* invokeWorkspaceTool<{ | 653 | const localConfig = yield* invokeWorkspaceTool<{ |
| 654 | defaultSecretStoreProvider: string; | 654 | defaultSecretStoreProvider: string; |
| @@ -723,11 +723,11 @@ describe("executor-runtime", () => { · 68 unmodified lines | |||
| 723 | expect(loadedPolicy.id).toBe(createdPolicy.id); | 723 | expect(loadedPolicy.id).toBe(createdPolicy.id); |
| 724 | 724 | ||
| 725 | const listedPolicies = yield* withExecutorApiClient( | 725 | const listedPolicies = yield* withExecutorApiClient( |
| 726 | { runtime, accountId: installation.accountId }, | 726 | { runtime, actorScopeId: installation.actorScopeId }, |
| 727 | (client) => | 727 | (client) => |
| 728 | client.policies.list({ | 728 | client.policies.list({ |
| 729 | path: { | 729 | path: { |
| 730 | workspaceId: installation.workspaceId, | 730 | workspaceId: installation.scopeId, |
| 731 | }, | 731 | }, |
| 732 | }), | 732 | }), |
| 733 | ); | 733 | ); |
| @@ -768,11 +768,11 @@ describe("executor-runtime", () => { · 34 unmodified lines | |||
| 768 | expect(removedSource.removed).toBe(true); | 768 | expect(removedSource.removed).toBe(true); |
| 769 | 769 | ||
| 770 | const apiSources = yield* withExecutorApiClient( | 770 | const apiSources = yield* withExecutorApiClient( |
| 771 | { runtime, accountId: installation.accountId }, | 771 | { runtime, actorScopeId: installation.actorScopeId }, |
| 772 | (client) => | 772 | (client) => |
| 773 | client.sources.list({ | 773 | client.sources.list({ |
| 774 | path: { | 774 | path: { |
| 775 | workspaceId: installation.workspaceId, | 775 | workspaceId: installation.scopeId, |
| 776 | }, | 776 | }, |
| 777 | }), | 777 | }), |
| 778 | ); | 778 | ); |
| @@ -798,8 +798,8 @@ describe("executor-runtime", () => { · 19 unmodified lines | |||
| 798 | 798 | ||
| 799 | yield* runtime.storage.executorState.executions.insert({ | 799 | yield* runtime.storage.executorState.executions.insert({ |
| 800 | id: executionId, | 800 | id: executionId, |
| 801 | workspaceId: installation.workspaceId, | 801 | scopeId: installation.scopeId, |
| 802 | createdByAccountId: installation.accountId, | 802 | createdByScopeId: installation.actorScopeId, |
| 803 | status: "running", | 803 | status: "running", |
| 804 | code: "return await tools.executor.sources.add(...)", | 804 | code: "return await tools.executor.sources.add(...)", |
| 805 | resultJson: null, | 805 | resultJson: null, |
| @@ -812,7 +812,7 @@ describe("executor-runtime", () => { · 6 unmodified lines | |||
| 812 | }); | 812 | }); |
| 813 | 813 | ||
| 814 | const localSource = yield* createSourceFromPayload({ | 814 | const localSource = yield* createSourceFromPayload({ |
| 815 | workspaceId: installation.workspaceId, | 815 | scopeId: installation.scopeId, |
| 816 | sourceId, | 816 | sourceId, |
| 817 | payload: { | 817 | payload: { |
| 818 | name: "GitHub", | 818 | name: "GitHub", |
| @@ -832,7 +832,7 @@ describe("executor-runtime", () => { · 13 unmodified lines | |||
| 832 | now, | 832 | now, |
| 833 | }).pipe(Effect.orDie); | 833 | }).pipe(Effect.orDie); |
| 834 | yield* persistSource(runtime.storage.executorState, localSource, { | 834 | yield* persistSource(runtime.storage.executorState, localSource, { |
| 835 | actorAccountId: installation.accountId, | 835 | actorScopeId: installation.actorScopeId, |
| 836 | }).pipe( | 836 | }).pipe( |
| 837 | (effect) => provideExecutorRuntime(effect, runtime), | 837 | (effect) => provideExecutorRuntime(effect, runtime), |
| 838 | Effect.orDie, | 838 | Effect.orDie, |
| @@ -854,13 +854,13 @@ describe("executor-runtime", () => { · 15 unmodified lines | |||
| 854 | endpoint: "https://api.github.com", | 854 | endpoint: "https://api.github.com", |
| 855 | specUrl: "https://example.com/github-openapi.yaml", | 855 | specUrl: "https://example.com/github-openapi.yaml", |
| 856 | name: "GitHub", | 856 | name: "GitHub", |
| 857 | workspaceId: installation.workspaceId, | 857 | scopeId: installation.scopeId, |
| 858 | sourceId, | 858 | sourceId, |
| 859 | }, | 859 | }, |
| 860 | elicitation: { | 860 | elicitation: { |
| 861 | mode: "url", | 861 | mode: "url", |
| 862 | message: "Open the secure credential page to connect GitHub", | 862 | message: "Open the secure credential page to connect GitHub", |
| 863 | url: `http://127.0.0.1/v1/workspaces/${encodeURIComponent(installation.workspaceId)}/sources/${encodeURIComponent(sourceId)}/credentials?interactionId=${encodeURIComponent(interactionId)}`, | 863 | url: `http://127.0.0.1/v1/workspaces/${encodeURIComponent(installation.scopeId)}/sources/${encodeURIComponent(sourceId)}/credentials?interactionId=${encodeURIComponent(interactionId)}`, |
| 864 | elicitationId: interactionSuffix, | 864 | elicitationId: interactionSuffix, |
| 865 | }, | 865 | }, |
| 866 | }); | 866 | }); |
| @@ -893,7 +893,7 @@ describe("executor-runtime", () => { · 26 unmodified lines | |||
| 893 | (handleRequest) => | 893 | (handleRequest) => |
| 894 | Effect.promise(async () => { | 894 | Effect.promise(async () => { |
| 895 | const url = new URL( | 895 | const url = new URL( |
| 896 | `/v1/workspaces/${encodeURIComponent(installation.workspaceId)}/sources/${encodeURIComponent(sourceId)}/credentials`, | 896 | `/v1/workspaces/${encodeURIComponent(installation.scopeId)}/sources/${encodeURIComponent(sourceId)}/credentials`, |
| 897 | "http://127.0.0.1", | 897 | "http://127.0.0.1", |
| 898 | ); | 898 | ); |
| 899 | url.searchParams.set("interactionId", pendingInteraction.value.id); | 899 | url.searchParams.set("interactionId", pendingInteraction.value.id); |
| @@ -910,7 +910,7 @@ describe("executor-runtime", () => { · 10 unmodified lines | |||
| 910 | (handleRequest) => | 910 | (handleRequest) => |
| 911 | Effect.promise(async () => { | 911 | Effect.promise(async () => { |
| 912 | const url = new URL( | 912 | const url = new URL( |
| 913 | `/v1/workspaces/${encodeURIComponent(installation.workspaceId)}/sources/${encodeURIComponent(sourceId)}/credentials`, | 913 | `/v1/workspaces/${encodeURIComponent(installation.scopeId)}/sources/${encodeURIComponent(sourceId)}/credentials`, |
| 914 | "http://127.0.0.1", | 914 | "http://127.0.0.1", |
| 915 | ); | 915 | ); |
| 916 | url.searchParams.set("interactionId", pendingInteraction.value.id); | 916 | url.searchParams.set("interactionId", pendingInteraction.value.id); |
| @@ -978,12 +978,12 @@ describe("executor-runtime", () => { · 61 unmodified lines | |||
| 978 | it.scoped("loads a v1.2.3-style workspace artifact on startup", () => | 978 | it.scoped("loads a v1.2.3-style workspace artifact on startup", () => |
| 979 | Effect.gen(function* () { | 979 | Effect.gen(function* () { |
| 980 | const fs = yield* FileSystem.FileSystem; | 980 | const fs = yield* FileSystem.FileSystem; |
| 981 | const workspaceRoot = yield* fs.makeTempDirectoryScoped({ | 981 | const scopeRoot = yield* fs.makeTempDirectoryScoped({ |
| 982 | prefix: "executor-runtime-v123-", | 982 | prefix: "executor-runtime-v123-", |
| 983 | }); | 983 | }); |
| 984 | const homeConfigPath = join(workspaceRoot, ".executor-home.jsonc"); | 984 | const homeConfigPath = join(scopeRoot, ".executor-home.jsonc"); |
| 985 | const homeStateDirectory = join(workspaceRoot, ".executor-home-state"); | 985 | const homeStateDirectory = join(scopeRoot, ".executor-home-state"); |
| 986 | const configDirectory = join(workspaceRoot, ".executor"); | 986 | const configDirectory = join(scopeRoot, ".executor"); |
| 987 | const configPath = join(configDirectory, "executor.jsonc"); | 987 | const configPath = join(configDirectory, "executor.jsonc"); |
| 988 | const sourceId = SourceIdSchema.make("graphql"); | 988 | const sourceId = SourceIdSchema.make("graphql"); |
| 989 | const now = Date.now(); | 989 | const now = Date.now(); |
| @@ -1010,13 +1010,13 @@ describe("executor-runtime", () => { · 20 unmodified lines | |||
| 1010 | ); | 1010 | ); |
| 1011 | 1011 | ||
| 1012 | const context = yield* resolveLocalWorkspaceContext({ | 1012 | const context = yield* resolveLocalWorkspaceContext({ |
| 1013 | workspaceRoot, | 1013 | workspaceRoot: scopeRoot, |
| 1014 | homeConfigPath, | 1014 | homeConfigPath, |
| 1015 | homeStateDirectory, | 1015 | homeStateDirectory, |
| 1016 | }); | 1016 | }); |
| 1017 | const installation = deriveLocalInstallation(context); | 1017 | const installation = deriveLocalInstallation(context); |
| 1018 | const source = yield* createSourceFromPayload({ | 1018 | const source = yield* createSourceFromPayload({ |
| 1019 | workspaceId: installation.workspaceId, | 1019 | scopeId: installation.scopeId, |
| 1020 | sourceId, | 1020 | sourceId, |
| 1021 | payload: { | 1021 | payload: { |
| 1022 | name: "GraphQL API", | 1022 | name: "GraphQL API", |
| @@ -1108,7 +1108,7 @@ describe("executor-runtime", () => { · 85 unmodified lines | |||
| 1108 | authArtifacts: [], | 1108 | authArtifacts: [], |
| 1109 | authLeases: [], | 1109 | authLeases: [], |
| 1110 | sourceOauthClients: [], | 1110 | sourceOauthClients: [], |
| 1111 | workspaceOauthClients: [], | 1111 | scopeOauthClients: [], |
| 1112 | providerAuthGrants: [], | 1112 | providerAuthGrants: [], |
| 1113 | sourceAuthSessions: [], | 1113 | sourceAuthSessions: [], |
| 1114 | secretMaterials: [], | 1114 | secretMaterials: [], |
| @@ -1145,7 +1145,7 @@ describe("executor-runtime", () => { · 30 unmodified lines | |||
| 1145 | 1145 | ||
| 1146 | const runtime = yield* Effect.acquireRelease( | 1146 | const runtime = yield* Effect.acquireRelease( |
| 1147 | createExecutorRuntime({ | 1147 | createExecutorRuntime({ |
| 1148 | workspaceRoot, | 1148 | workspaceRoot: scopeRoot, |
| 1149 | homeConfigPath, | 1149 | homeConfigPath, |
| 1150 | homeStateDirectory, | 1150 | homeStateDirectory, |
| 1151 | }), | 1151 | }), |
| @@ -1154,11 +1154,11 @@ describe("executor-runtime", () => { · 2 unmodified lines | |||
| 1154 | ); | 1154 | ); |
| 1155 | 1155 | ||
| 1156 | const inspection = yield* withExecutorApiClient( | 1156 | const inspection = yield* withExecutorApiClient( |
| 1157 | { runtime, accountId: installation.accountId }, | 1157 | { runtime, actorScopeId: installation.actorScopeId }, |
| 1158 | (client) => | 1158 | (client) => |
| 1159 | client.sources.inspection({ | 1159 | client.sources.inspection({ |
| 1160 | path: { | 1160 | path: { |
| 1161 | workspaceId: installation.workspaceId, | 1161 | workspaceId: installation.scopeId, |
| 1162 | sourceId, | 1162 | sourceId, |
| 1163 | }, | 1163 | }, |
| 1164 | }), | 1164 | }), |
| @@ -1179,13 +1179,13 @@ describe("executor-runtime", () => { · 14 unmodified lines | |||
| 1179 | Effect.gen(function* () { | 1179 | Effect.gen(function* () { |
| 1180 | const fs = yield* FileSystem.FileSystem; | 1180 | const fs = yield* FileSystem.FileSystem; |
| 1181 | const openApiServer = yield* makeOpenApiSpecServer; | 1181 | const openApiServer = yield* makeOpenApiSpecServer; |
| 1182 | const workspaceRoot = yield* fs.makeTempDirectoryScoped({ | 1182 | const scopeRoot = yield* fs.makeTempDirectoryScoped({ |
| 1183 | prefix: "executor-runtime-startup-rebuild-", | 1183 | prefix: "executor-runtime-startup-rebuild-", |
| 1184 | }); | 1184 | }); |
| 1185 | const homeConfigPath = join(workspaceRoot, ".executor-home.jsonc"); | 1185 | const homeConfigPath = join(scopeRoot, ".executor-home.jsonc"); |
| 1186 | const homeStateDirectory = join(workspaceRoot, ".executor-home-state"); | 1186 | const homeStateDirectory = join(scopeRoot, ".executor-home-state"); |
| 1187 | const context = yield* resolveLocalWorkspaceContext({ | 1187 | const context = yield* resolveLocalWorkspaceContext({ |
| 1188 | workspaceRoot, | 1188 | workspaceRoot: scopeRoot, |
| 1189 | homeConfigPath, | 1189 | homeConfigPath, |
| 1190 | homeStateDirectory, | 1190 | homeStateDirectory, |
| 1191 | }); | 1191 | }); |
| @@ -1193,7 +1193,7 @@ describe("executor-runtime", () => { · 1 unmodified line | |||
| 1193 | const sourceId = SourceIdSchema.make("github"); | 1193 | const sourceId = SourceIdSchema.make("github"); |
| 1194 | const now = Date.now(); | 1194 | const now = Date.now(); |
| 1195 | const source = yield* createSourceFromPayload({ | 1195 | const source = yield* createSourceFromPayload({ |
| 1196 | workspaceId: installation.workspaceId, | 1196 | scopeId: installation.scopeId, |
| 1197 | sourceId, | 1197 | sourceId, |
| 1198 | payload: { | 1198 | payload: { |
| 1199 | name: "GitHub", | 1199 | name: "GitHub", |
| @@ -1251,7 +1251,7 @@ describe("executor-runtime", () => { · 51 unmodified lines | |||
| 1251 | 1251 | ||
| 1252 | const runtime = yield* Effect.acquireRelease( | 1252 | const runtime = yield* Effect.acquireRelease( |
| 1253 | createExecutorRuntime({ | 1253 | createExecutorRuntime({ |
| 1254 | workspaceRoot, | 1254 | workspaceRoot: scopeRoot, |
| 1255 | homeConfigPath, | 1255 | homeConfigPath, |
| 1256 | homeStateDirectory, | 1256 | homeStateDirectory, |
| 1257 | }), | 1257 | }), |
| @@ -1266,11 +1266,11 @@ describe("executor-runtime", () => { · 8 unmodified lines | |||
| 1266 | expect(rebuiltArtifact).not.toBeNull(); | 1266 | expect(rebuiltArtifact).not.toBeNull(); |
| 1267 | 1267 | ||
| 1268 | const inspection = yield* withExecutorApiClient( | 1268 | const inspection = yield* withExecutorApiClient( |
| 1269 | { runtime, accountId: installation.accountId }, | 1269 | { runtime, actorScopeId: installation.actorScopeId }, |
| 1270 | (client) => | 1270 | (client) => |
| 1271 | client.sources.inspection({ | 1271 | client.sources.inspection({ |
| 1272 | path: { | 1272 | path: { |
| 1273 | workspaceId: installation.workspaceId, | 1273 | workspaceId: installation.scopeId, |
| 1274 | sourceId, | 1274 | sourceId, |
| 1275 | }, | 1275 | }, |
| 1276 | }), | 1276 | }), |
| @@ -1290,7 +1290,7 @@ describe("executor-runtime", () => { · 13 unmodified lines | |||
| 1290 | const now = Date.now(); | 1290 | const now = Date.now(); |
| 1291 | 1291 | ||
| 1292 | const localSource = yield* createSourceFromPayload({ | 1292 | const localSource = yield* createSourceFromPayload({ |
| 1293 | workspaceId: installation.workspaceId, | 1293 | scopeId: installation.scopeId, |
| 1294 | sourceId, | 1294 | sourceId, |
| 1295 | payload: { | 1295 | payload: { |
| 1296 | name: "Google Drive", | 1296 | name: "Google Drive", |
| @@ -1314,18 +1314,18 @@ describe("executor-runtime", () => { · 17 unmodified lines | |||
| 1314 | now, | 1314 | now, |
| 1315 | }).pipe(Effect.orDie); | 1315 | }).pipe(Effect.orDie); |
| 1316 | yield* persistSource(runtime.storage.executorState, localSource, { | 1316 | yield* persistSource(runtime.storage.executorState, localSource, { |
| 1317 | actorAccountId: installation.accountId, | 1317 | actorScopeId: installation.actorScopeId, |
| 1318 | }).pipe( | 1318 | }).pipe( |
| 1319 | (effect) => provideExecutorRuntime(effect, runtime), | 1319 | (effect) => provideExecutorRuntime(effect, runtime), |
| 1320 | Effect.orDie, | 1320 | Effect.orDie, |
| 1321 | ); | 1321 | ); |
| 1322 | 1322 | ||
| 1323 | const inspection = yield* withExecutorApiClient( | 1323 | const inspection = yield* withExecutorApiClient( |
| 1324 | { runtime, accountId: installation.accountId }, | 1324 | { runtime, actorScopeId: installation.actorScopeId }, |
| 1325 | (client) => | 1325 | (client) => |
| 1326 | client.sources.inspection({ | 1326 | client.sources.inspection({ |
| 1327 | path: { | 1327 | path: { |
| 1328 | workspaceId: installation.workspaceId, | 1328 | workspaceId: installation.scopeId, |
| 1329 | sourceId, | 1329 | sourceId, |
| 1330 | }, | 1330 | }, |
| 1331 | }), | 1331 | }), |
| @@ -1348,7 +1348,7 @@ describe("executor-runtime", () => { · 16 unmodified lines | |||
| 1348 | const now = Date.now(); | 1348 | const now = Date.now(); |
| 1349 | 1349 | ||
| 1350 | const localSource = yield* createSourceFromPayload({ | 1350 | const localSource = yield* createSourceFromPayload({ |
| 1351 | workspaceId: installation.workspaceId, | 1351 | scopeId: installation.scopeId, |
| 1352 | sourceId, | 1352 | sourceId, |
| 1353 | payload: { | 1353 | payload: { |
| 1354 | name: "Google Drive", | 1354 | name: "Google Drive", |
| @@ -1372,7 +1372,7 @@ describe("executor-runtime", () => { · 17 unmodified lines | |||
| 1372 | now, | 1372 | now, |
| 1373 | }).pipe(Effect.orDie); | 1373 | }).pipe(Effect.orDie); |
| 1374 | yield* persistSource(runtime.storage.executorState, localSource, { | 1374 | yield* persistSource(runtime.storage.executorState, localSource, { |
| 1375 | actorAccountId: installation.accountId, | 1375 | actorScopeId: installation.actorScopeId, |
| 1376 | }).pipe( | 1376 | }).pipe( |
| 1377 | (effect) => provideExecutorRuntime(effect, runtime), | 1377 | (effect) => provideExecutorRuntime(effect, runtime), |
| 1378 | Effect.orDie, | 1378 | Effect.orDie, |
| @@ -1380,11 +1380,11 @@ describe("executor-runtime", () => { · 1 unmodified line | |||
| 1380 | 1380 | ||
| 1381 | const error = yield* expectLeft( | 1381 | const error = yield* expectLeft( |
| 1382 | withExecutorApiClient( | 1382 | withExecutorApiClient( |
| 1383 | { runtime, accountId: installation.accountId }, | 1383 | { runtime, actorScopeId: installation.actorScopeId }, |
| 1384 | (client) => | 1384 | (client) => |
| 1385 | client.sources.inspection({ | 1385 | client.sources.inspection({ |
| 1386 | path: { | 1386 | path: { |
| 1387 | workspaceId: installation.workspaceId, | 1387 | workspaceId: installation.scopeId, |
| 1388 | sourceId, | 1388 | sourceId, |
| 1389 | }, | 1389 | }, |
| 1390 | }), | 1390 | }), |
| @@ -1415,8 +1415,8 @@ describe("executor-runtime", () => { · 24 unmodified lines | |||
| 1415 | 1415 | ||
| 1416 | yield* runtime.storage.executorState.executions.insert({ | 1416 | yield* runtime.storage.executorState.executions.insert({ |
| 1417 | id: executionId, | 1417 | id: executionId, |
| 1418 | workspaceId: installation.workspaceId, | 1418 | scopeId: installation.scopeId, |
| 1419 | createdByAccountId: installation.accountId, | 1419 | createdByScopeId: installation.actorScopeId, |
| 1420 | status: "running", | 1420 | status: "running", |
| 1421 | code: "return await tools.executor.sources.add(...)", | 1421 | code: "return await tools.executor.sources.add(...)", |
| 1422 | resultJson: null, | 1422 | resultJson: null, |
| @@ -1429,7 +1429,7 @@ describe("executor-runtime", () => { · 6 unmodified lines | |||
| 1429 | }); | 1429 | }); |
| 1430 | 1430 | ||
| 1431 | const localSource = yield* createSourceFromPayload({ | 1431 | const localSource = yield* createSourceFromPayload({ |
| 1432 | workspaceId: installation.workspaceId, | 1432 | scopeId: installation.scopeId, |
| 1433 | sourceId, | 1433 | sourceId, |
| 1434 | payload: { | 1434 | payload: { |
| 1435 | name: "GitHub", | 1435 | name: "GitHub", |
| @@ -1449,7 +1449,7 @@ describe("executor-runtime", () => { · 13 unmodified lines | |||
| 1449 | now, | 1449 | now, |
| 1450 | }).pipe(Effect.orDie); | 1450 | }).pipe(Effect.orDie); |
| 1451 | yield* persistSource(runtime.storage.executorState, localSource, { | 1451 | yield* persistSource(runtime.storage.executorState, localSource, { |
| 1452 | actorAccountId: installation.accountId, | 1452 | actorScopeId: installation.actorScopeId, |
| 1453 | }).pipe( | 1453 | }).pipe( |
| 1454 | (effect) => provideExecutorRuntime(effect, runtime), | 1454 | (effect) => provideExecutorRuntime(effect, runtime), |
| 1455 | Effect.orDie, | 1455 | Effect.orDie, |
| @@ -1471,13 +1471,13 @@ describe("executor-runtime", () => { · 15 unmodified lines | |||
| 1471 | endpoint: "https://api.github.com", | 1471 | endpoint: "https://api.github.com", |
| 1472 | specUrl: "https://example.com/github-openapi.yaml", | 1472 | specUrl: "https://example.com/github-openapi.yaml", |
| 1473 | name: "GitHub", | 1473 | name: "GitHub", |
| 1474 | workspaceId: installation.workspaceId, | 1474 | scopeId: installation.scopeId, |
| 1475 | sourceId, | 1475 | sourceId, |
| 1476 | }, | 1476 | }, |
| 1477 | elicitation: { | 1477 | elicitation: { |
| 1478 | mode: "url", | 1478 | mode: "url", |
| 1479 | message: "Open the secure credential page to connect GitHub", | 1479 | message: "Open the secure credential page to connect GitHub", |
| 1480 | url: `http://127.0.0.1/v1/workspaces/${encodeURIComponent(installation.workspaceId)}/sources/${encodeURIComponent(sourceId)}/credentials?interactionId=${encodeURIComponent(interactionId)}`, | 1480 | url: `http://127.0.0.1/v1/workspaces/${encodeURIComponent(installation.scopeId)}/sources/${encodeURIComponent(sourceId)}/credentials?interactionId=${encodeURIComponent(interactionId)}`, |
| 1481 | elicitationId: interactionSuffix, | 1481 | elicitationId: interactionSuffix, |
| 1482 | }, | 1482 | }, |
| 1483 | }); | 1483 | }); |
| @@ -1505,7 +1505,7 @@ describe("executor-runtime", () => { · 21 unmodified lines | |||
| 1505 | assertTrue(Option.isSome(pendingInteraction)); | 1505 | assertTrue(Option.isSome(pendingInteraction)); |
| 1506 | 1506 | ||
| 1507 | const submitted = yield* submitSourceCredentialInteraction({ | 1507 | const submitted = yield* submitSourceCredentialInteraction({ |
| 1508 | workspaceId: installation.workspaceId, | 1508 | scopeId: installation.scopeId, |
| 1509 | sourceId, | 1509 | sourceId, |
| 1510 | interactionId: pendingInteraction.value.id, | 1510 | interactionId: pendingInteraction.value.id, |
| 1511 | action: "continue", | 1511 | action: "continue", |
| @@ -1538,7 +1538,7 @@ describe("executor-runtime", () => { · 26 unmodified lines | |||
| 1538 | const executionId = ExecutionIdSchema.make( | 1538 | const executionId = ExecutionIdSchema.make( |
| 1539 | "exec_local_graphql_credential_continue", | 1539 | "exec_local_graphql_credential_continue", |
| 1540 | ); | 1540 | ); |
| 1541 | const workspaceId = "ws_local_graphql" as const; | 1541 | const scopeId = "ws_local_graphql" as const; |
| 1542 | const sourceId = SourceIdSchema.make("graphql_api"); | 1542 | const sourceId = SourceIdSchema.make("graphql_api"); |
| 1543 | const now = Date.now(); | 1543 | const now = Date.now(); |
| 1544 | const decoded = decodeSourceCredentialInteraction({ | 1544 | const decoded = decodeSourceCredentialInteraction({ |
| @@ -1555,7 +1555,7 @@ describe("executor-runtime", () => { · 10 unmodified lines | |||
| 1555 | endpoint: "https://example.com/graphql", | 1555 | endpoint: "https://example.com/graphql", |
| 1556 | name: "GraphQL API", | 1556 | name: "GraphQL API", |
| 1557 | namespace: "graphql", | 1557 | namespace: "graphql", |
| 1558 | workspaceId, | 1558 | scopeId, |
| 1559 | sourceId, | 1559 | sourceId, |
| 1560 | }, | 1560 | }, |
| 1561 | elicitation: { | 1561 | elicitation: { |
| @@ -1570,7 +1570,7 @@ describe("executor-runtime", () => { · 8 unmodified lines | |||
| 1570 | }); | 1570 | }); |
| 1571 | 1571 | ||
| 1572 | expect(decoded).not.toBeNull(); | 1572 | expect(decoded).not.toBeNull(); |
| 1573 | expect(decoded?.workspaceId).toBe(workspaceId); | 1573 | expect(decoded?.scopeId).toBe(scopeId); |
| 1574 | expect(decoded?.sourceId).toBe(sourceId); | 1574 | expect(decoded?.sourceId).toBe(sourceId); |
| 1575 | expect(decoded?.message).toContain("GraphQL API"); | 1575 | expect(decoded?.message).toContain("GraphQL API"); |
| 1576 | }), | 1576 | }), |
| @@ -1589,7 +1589,7 @@ describe("executor-runtime", () => { · 12 unmodified lines | |||
| 1589 | (client) => | 1589 | (client) => |
| 1590 | client.sources.createWorkspaceOauthClient({ | 1590 | client.sources.createWorkspaceOauthClient({ |
| 1591 | path: { | 1591 | path: { |
| 1592 | workspaceId: installation.workspaceId, | 1592 | workspaceId: installation.scopeId, |
| 1593 | }, | 1593 | }, |
| 1594 | payload: { | 1594 | payload: { |
| 1595 | providerKey: "google_workspace", | 1595 | providerKey: "google_workspace", |
| @@ -1615,8 +1615,8 @@ describe("executor-runtime", () => { · 19 unmodified lines | |||
| 1615 | ); | 1615 | ); |
| 1616 | yield* runtime.storage.executorState.providerAuthGrants.upsert({ | 1616 | yield* runtime.storage.executorState.providerAuthGrants.upsert({ |
| 1617 | id: grantId, | 1617 | id: grantId, |
| 1618 | workspaceId: installation.workspaceId, | 1618 | scopeId: installation.scopeId, |
| 1619 | actorAccountId: installation.accountId, | 1619 | actorScopeId: installation.actorScopeId, |
| 1620 | providerKey: "google_workspace", | 1620 | providerKey: "google_workspace", |
| 1621 | oauthClientId: oauthClient.id, | 1621 | oauthClientId: oauthClient.id, |
| 1622 | tokenEndpoint: googleServer.tokenEndpoint, | 1622 | tokenEndpoint: googleServer.tokenEndpoint, |
| @@ -1642,11 +1642,11 @@ describe("executor-runtime", () => { · 19 unmodified lines | |||
| 1642 | const result = yield* withExecutorApiClient({ runtime }, (client) => | 1642 | const result = yield* withExecutorApiClient({ runtime }, (client) => |
| 1643 | client.sources.connect({ | 1643 | client.sources.connect({ |
| 1644 | path: { | 1644 | path: { |
| 1645 | workspaceId: installation.workspaceId, | 1645 | workspaceId: installation.scopeId, |
| 1646 | }, | 1646 | }, |
| 1647 | payload: { | 1647 | payload: { |
| 1648 | kind: "google_discovery", | 1648 | kind: "google_discovery", |
| 1649 | workspaceOauthClientId: oauthClient.id, | 1649 | scopeOauthClientId: oauthClient.id, |
| 1650 | service: "drive", | 1650 | service: "drive", |
| 1651 | version: "v3", | 1651 | version: "v3", |
| 1652 | discoveryUrl: googleServer.discoveryUrl({ | 1652 | discoveryUrl: googleServer.discoveryUrl({ |
| @@ -1698,7 +1698,7 @@ describe("executor-runtime", () => { · 45 unmodified lines | |||
| 1698 | (client) => | 1698 | (client) => |
| 1699 | client.sources.createWorkspaceOauthClient({ | 1699 | client.sources.createWorkspaceOauthClient({ |
| 1700 | path: { | 1700 | path: { |
| 1701 | workspaceId: installation.workspaceId, | 1701 | workspaceId: installation.scopeId, |
| 1702 | }, | 1702 | }, |
| 1703 | payload: { | 1703 | payload: { |
| 1704 | providerKey: "google_workspace", | 1704 | providerKey: "google_workspace", |
| @@ -1714,11 +1714,11 @@ describe("executor-runtime", () => { · 9 unmodified lines | |||
| 1714 | const result = yield* withExecutorApiClient({ runtime }, (client) => | 1714 | const result = yield* withExecutorApiClient({ runtime }, (client) => |
| 1715 | client.sources.connect({ | 1715 | client.sources.connect({ |
| 1716 | path: { | 1716 | path: { |
| 1717 | workspaceId: installation.workspaceId, | 1717 | workspaceId: installation.scopeId, |
| 1718 | }, | 1718 | }, |
| 1719 | payload: { | 1719 | payload: { |
| 1720 | kind: "google_discovery", | 1720 | kind: "google_discovery", |
| 1721 | workspaceOauthClientId: oauthClient.id, | 1721 | scopeOauthClientId: oauthClient.id, |
| 1722 | service: "gmail", | 1722 | service: "gmail", |
| 1723 | version: "v1", | 1723 | version: "v1", |
| 1724 | discoveryUrl: googleServer.discoveryUrl({ | 1724 | discoveryUrl: googleServer.discoveryUrl({ |
| @@ -1745,7 +1745,7 @@ describe("executor-runtime", () => { · 20 unmodified lines | |||
| 1745 | ); | 1745 | ); |
| 1746 | expect(redirectUri).not.toBeNull(); | 1746 | expect(redirectUri).not.toBeNull(); |
| 1747 | expect(new URL(redirectUri!).pathname).toBe( | 1747 | expect(new URL(redirectUri!).pathname).toBe( |
| 1748 | `/v1/workspaces/${encodeURIComponent(installation.workspaceId)}/oauth/provider/callback`, | 1748 | `/v1/workspaces/${encodeURIComponent(installation.scopeId)}/oauth/provider/callback`, |
| 1749 | ); | 1749 | ); |
| 1750 | expect(result.source.status).toBe("auth_required"); | 1750 | expect(result.source.status).toBe("auth_required"); |
| 1751 | }), | 1751 | }), |
| @@ -1765,7 +1765,7 @@ describe("executor-runtime", () => { · 13 unmodified lines | |||
| 1765 | (client) => | 1765 | (client) => |
| 1766 | client.sources.createWorkspaceOauthClient({ | 1766 | client.sources.createWorkspaceOauthClient({ |
| 1767 | path: { | 1767 | path: { |
| 1768 | workspaceId: installation.workspaceId, | 1768 | workspaceId: installation.scopeId, |
| 1769 | }, | 1769 | }, |
| 1770 | payload: { | 1770 | payload: { |
| 1771 | providerKey: "google_workspace", | 1771 | providerKey: "google_workspace", |
| @@ -1791,8 +1791,8 @@ describe("executor-runtime", () => { · 19 unmodified lines | |||
| 1791 | ); | 1791 | ); |
| 1792 | yield* runtime.storage.executorState.providerAuthGrants.upsert({ | 1792 | yield* runtime.storage.executorState.providerAuthGrants.upsert({ |
| 1793 | id: grantId, | 1793 | id: grantId, |
| 1794 | workspaceId: installation.workspaceId, | 1794 | scopeId: installation.scopeId, |
| 1795 | actorAccountId: installation.accountId, | 1795 | actorScopeId: installation.actorScopeId, |
| 1796 | providerKey: "google_workspace", | 1796 | providerKey: "google_workspace", |
| 1797 | oauthClientId: oauthClient.id, | 1797 | oauthClientId: oauthClient.id, |
| 1798 | tokenEndpoint: googleServer.tokenEndpoint, | 1798 | tokenEndpoint: googleServer.tokenEndpoint, |
| @@ -1822,10 +1822,10 @@ describe("executor-runtime", () => { · 23 unmodified lines | |||
| 1822 | const result = yield* withExecutorApiClient({ runtime }, (client) => | 1822 | const result = yield* withExecutorApiClient({ runtime }, (client) => |
| 1823 | client.sources.connectBatch({ | 1823 | client.sources.connectBatch({ |
| 1824 | path: { | 1824 | path: { |
| 1825 | workspaceId: installation.workspaceId, | 1825 | workspaceId: installation.scopeId, |
| 1826 | }, | 1826 | }, |
| 1827 | payload: { | 1827 | payload: { |
| 1828 | workspaceOauthClientId: oauthClient.id, | 1828 | scopeOauthClientId: oauthClient.id, |
| 1829 | sources: [ | 1829 | sources: [ |
| 1830 | { | 1830 | { |
| 1831 | service: "gmail", | 1831 | service: "gmail", |
| @@ -1894,7 +1894,7 @@ describe("executor-runtime", () => { · 62 unmodified lines | |||
| 1894 | (client) => | 1894 | (client) => |
| 1895 | client.sources.createWorkspaceOauthClient({ | 1895 | client.sources.createWorkspaceOauthClient({ |
| 1896 | path: { | 1896 | path: { |
| 1897 | workspaceId: installation.workspaceId, | 1897 | workspaceId: installation.scopeId, |
| 1898 | }, | 1898 | }, |
| 1899 | payload: { | 1899 | payload: { |
| 1900 | providerKey: "google_workspace", | 1900 | providerKey: "google_workspace", |
| @@ -1910,10 +1910,10 @@ describe("executor-runtime", () => { · 9 unmodified lines | |||
| 1910 | const result = yield* withExecutorApiClient({ runtime }, (client) => | 1910 | const result = yield* withExecutorApiClient({ runtime }, (client) => |
| 1911 | client.sources.connectBatch({ | 1911 | client.sources.connectBatch({ |
| 1912 | path: { | 1912 | path: { |
| 1913 | workspaceId: installation.workspaceId, | 1913 | workspaceId: installation.scopeId, |
| 1914 | }, | 1914 | }, |
| 1915 | payload: { | 1915 | payload: { |
| 1916 | workspaceOauthClientId: oauthClient.id, | 1916 | scopeOauthClientId: oauthClient.id, |
| 1917 | sources: [ | 1917 | sources: [ |
| 1918 | { | 1918 | { |
| 1919 | service: "gmail", | 1919 | service: "gmail", |
| @@ -1939,7 +1939,7 @@ describe("executor-runtime", () => { · 19 unmodified lines | |||
| 1939 | 1939 | ||
| 1940 | expect(redirectUri).not.toBeNull(); | 1940 | expect(redirectUri).not.toBeNull(); |
| 1941 | expect(new URL(redirectUri!).pathname).toBe( | 1941 | expect(new URL(redirectUri!).pathname).toBe( |
| 1942 | `/v1/workspaces/${encodeURIComponent(installation.workspaceId)}/oauth/provider/callback`, | 1942 | `/v1/workspaces/${encodeURIComponent(installation.scopeId)}/oauth/provider/callback`, |
| 1943 | ); | 1943 | ); |
| 1944 | }), | 1944 | }), |
| 1945 | 60_000, | 1945 | 60_000, |
| @@ -1958,7 +1958,7 @@ describe("executor-runtime", () => { · 12 unmodified lines | |||
| 1958 | (client) => | 1958 | (client) => |
| 1959 | client.sources.createWorkspaceOauthClient({ | 1959 | client.sources.createWorkspaceOauthClient({ |
| 1960 | path: { | 1960 | path: { |
| 1961 | workspaceId: installation.workspaceId, | 1961 | workspaceId: installation.scopeId, |
| 1962 | }, | 1962 | }, |
| 1963 | payload: { | 1963 | payload: { |
| 1964 | providerKey: "google_workspace", | 1964 | providerKey: "google_workspace", |
| @@ -2001,8 +2001,8 @@ describe("executor-runtime", () => { · 36 unmodified lines | |||
| 2001 | ); | 2001 | ); |
| 2002 | yield* runtime.storage.executorState.providerAuthGrants.upsert({ | 2002 | yield* runtime.storage.executorState.providerAuthGrants.upsert({ |
| 2003 | id: grantId, | 2003 | id: grantId, |
| 2004 | workspaceId: installation.workspaceId, | 2004 | scopeId: installation.scopeId, |
| 2005 | actorAccountId: installation.accountId, | 2005 | actorScopeId: installation.actorScopeId, |
| 2006 | providerKey: "google_workspace", | 2006 | providerKey: "google_workspace", |
| 2007 | oauthClientId: oauthClient.id, | 2007 | oauthClientId: oauthClient.id, |
| 2008 | tokenEndpoint: googleServer.tokenEndpoint, | 2008 | tokenEndpoint: googleServer.tokenEndpoint, |
| @@ -2026,11 +2026,11 @@ describe("executor-runtime", () => { · 17 unmodified lines | |||
| 2026 | const state = `provider-state-${crypto.randomUUID()}`; | 2026 | const state = `provider-state-${crypto.randomUUID()}`; |
| 2027 | yield* runtime.storage.executorState.sourceAuthSessions.upsert({ | 2027 | yield* runtime.storage.executorState.sourceAuthSessions.upsert({ |
| 2028 | id: sessionId, | 2028 | id: sessionId, |
| 2029 | workspaceId: installation.workspaceId, | 2029 | scopeId: installation.scopeId, |
| 2030 | sourceId: SourceIdSchema.make( | 2030 | sourceId: SourceIdSchema.make( |
| 2031 | `oauth_provider_${crypto.randomUUID()}`, | 2031 | `oauth_provider_${crypto.randomUUID()}`, |
| 2032 | ), | 2032 | ), |
| 2033 | actorAccountId: installation.accountId, | 2033 | actorScopeId: installation.actorScopeId, |
| 2034 | credentialSlot: "runtime", | 2034 | credentialSlot: "runtime", |
| 2035 | executionId: null, | 2035 | executionId: null, |
| 2036 | interactionId: null, | 2036 | interactionId: null, |
| @@ -2083,7 +2083,7 @@ describe("executor-runtime", () => { · 46 unmodified lines | |||
| 2083 | (client) => | 2083 | (client) => |
| 2084 | client.sources.providerOauthComplete({ | 2084 | client.sources.providerOauthComplete({ |
| 2085 | path: { | 2085 | path: { |
| 2086 | workspaceId: installation.workspaceId, | 2086 | workspaceId: installation.scopeId, |
| 2087 | }, | 2087 | }, |
| 2088 | urlParams: { | 2088 | urlParams: { |
| 2089 | state, | 2089 | state, |
| @@ -2111,7 +2111,7 @@ describe("executor-runtime", () => { · 21 unmodified lines | |||
| 2111 | (client) => | 2111 | (client) => |
| 2112 | client.sources.get({ | 2112 | client.sources.get({ |
| 2113 | path: { | 2113 | path: { |
| 2114 | workspaceId: installation.workspaceId, | 2114 | workspaceId: installation.scopeId, |
| 2115 | sourceId: source.id, | 2115 | sourceId: source.id, |
| 2116 | }, | 2116 | }, |
| 2117 | }), | 2117 | }), |
| @@ -2148,14 +2148,14 @@ describe("executor-runtime", () => { · 30 unmodified lines | |||
| 2148 | Effect.gen(function* () { | 2148 | Effect.gen(function* () { |
| 2149 | const runtime = yield* makeRuntime; | 2149 | const runtime = yield* makeRuntime; |
| 2150 | const installation = runtime.localInstallation; | 2150 | const installation = runtime.localInstallation; |
| 2151 | const oauthClientId = WorkspaceOauthClientIdSchema.make( | 2151 | const oauthClientId = ScopeOauthClientIdSchema.make( |
| 2152 | `ws_oauth_client_${crypto.randomUUID()}`, | 2152 | `ws_oauth_client_${crypto.randomUUID()}`, |
| 2153 | ); | 2153 | ); |
| 2154 | const refreshSecretId = "sec_google_refresh_orphan"; | 2154 | const refreshSecretId = "sec_google_refresh_orphan"; |
| 2155 | 2155 | ||
| 2156 | yield* runtime.storage.executorState.workspaceOauthClients.upsert({ | 2156 | yield* runtime.storage.executorState.scopeOauthClients.upsert({ |
| 2157 | id: oauthClientId, | 2157 | id: oauthClientId, |
| 2158 | workspaceId: installation.workspaceId, | 2158 | scopeId: installation.scopeId, |
| 2159 | providerKey: "google_workspace", | 2159 | providerKey: "google_workspace", |
| 2160 | label: "Local Google Workspace Client", | 2160 | label: "Local Google Workspace Client", |
| 2161 | clientId: "google-client-id", | 2161 | clientId: "google-client-id", |
| @@ -2177,8 +2177,8 @@ describe("executor-runtime", () => { · 15 unmodified lines | |||
| 2177 | ); | 2177 | ); |
| 2178 | yield* runtime.storage.executorState.providerAuthGrants.upsert({ | 2178 | yield* runtime.storage.executorState.providerAuthGrants.upsert({ |
| 2179 | id: grantId, | 2179 | id: grantId, |
| 2180 | workspaceId: installation.workspaceId, | 2180 | scopeId: installation.scopeId, |
| 2181 | actorAccountId: installation.accountId, | 2181 | actorScopeId: installation.actorScopeId, |
| 2182 | providerKey: "google_workspace", | 2182 | providerKey: "google_workspace", |
| 2183 | oauthClientId, | 2183 | oauthClientId, |
| 2184 | tokenEndpoint: "https://example.test/oauth/token", | 2184 | tokenEndpoint: "https://example.test/oauth/token", |
| @@ -2217,7 +2217,7 @@ describe("executor-runtime", () => { · 32 unmodified lines | |||
| 2217 | const removed = yield* withExecutorApiClient({ runtime }, (client) => | 2217 | const removed = yield* withExecutorApiClient({ runtime }, (client) => |
| 2218 | client.sources.remove({ | 2218 | client.sources.remove({ |
| 2219 | path: { | 2219 | path: { |
| 2220 | workspaceId: installation.workspaceId, | 2220 | workspaceId: installation.scopeId, |
| 2221 | sourceId: source.id, | 2221 | sourceId: source.id, |
| 2222 | }, | 2222 | }, |
| 2223 | }), | 2223 | }), |
| @@ -2238,14 +2238,14 @@ describe("executor-runtime", () => { · 14 unmodified lines | |||
| 2238 | Effect.gen(function* () { | 2238 | Effect.gen(function* () { |
| 2239 | const runtime = yield* makeRuntime; | 2239 | const runtime = yield* makeRuntime; |
| 2240 | const installation = runtime.localInstallation; | 2240 | const installation = runtime.localInstallation; |
| 2241 | const oauthClientId = WorkspaceOauthClientIdSchema.make( | 2241 | const oauthClientId = ScopeOauthClientIdSchema.make( |
| 2242 | `ws_oauth_client_${crypto.randomUUID()}`, | 2242 | `ws_oauth_client_${crypto.randomUUID()}`, |
| 2243 | ); | 2243 | ); |
| 2244 | const refreshSecretId = "sec_google_refresh_revoke"; | 2244 | const refreshSecretId = "sec_google_refresh_revoke"; |
| 2245 | 2245 | ||
| 2246 | yield* runtime.storage.executorState.workspaceOauthClients.upsert({ | 2246 | yield* runtime.storage.executorState.scopeOauthClients.upsert({ |
| 2247 | id: oauthClientId, | 2247 | id: oauthClientId, |
| 2248 | workspaceId: installation.workspaceId, | 2248 | scopeId: installation.scopeId, |
| 2249 | providerKey: "google_workspace", | 2249 | providerKey: "google_workspace", |
| 2250 | label: "Local Google Workspace Client", | 2250 | label: "Local Google Workspace Client", |
| 2251 | clientId: "google-client-id", | 2251 | clientId: "google-client-id", |
| @@ -2267,8 +2267,8 @@ describe("executor-runtime", () => { · 15 unmodified lines | |||
| 2267 | ); | 2267 | ); |
| 2268 | yield* runtime.storage.executorState.providerAuthGrants.upsert({ | 2268 | yield* runtime.storage.executorState.providerAuthGrants.upsert({ |
| 2269 | id: grantId, | 2269 | id: grantId, |
| 2270 | workspaceId: installation.workspaceId, | 2270 | scopeId: installation.scopeId, |
| 2271 | actorAccountId: installation.accountId, | 2271 | actorScopeId: installation.actorScopeId, |
| 2272 | providerKey: "google_workspace", | 2272 | providerKey: "google_workspace", |
| 2273 | oauthClientId, | 2273 | oauthClientId, |
| 2274 | tokenEndpoint: "https://example.test/oauth/token", | 2274 | tokenEndpoint: "https://example.test/oauth/token", |
| @@ -2324,7 +2324,7 @@ describe("executor-runtime", () => { · 49 unmodified lines | |||
| 2324 | const removed = yield* withExecutorApiClient({ runtime }, (client) => | 2324 | const removed = yield* withExecutorApiClient({ runtime }, (client) => |
| 2325 | client.sources.removeProviderAuthGrant({ | 2325 | client.sources.removeProviderAuthGrant({ |
| 2326 | path: { | 2326 | path: { |
| 2327 | workspaceId: installation.workspaceId, | 2327 | workspaceId: installation.scopeId, |
| 2328 | grantId, | 2328 | grantId, |
| 2329 | }, | 2329 | }, |
| 2330 | }), | 2330 | }), |
| @@ -2347,7 +2347,7 @@ describe("executor-runtime", () => { · 16 unmodified lines | |||
| 2347 | (client) => | 2347 | (client) => |
| 2348 | client.sources.get({ | 2348 | client.sources.get({ |
| 2349 | path: { | 2349 | path: { |
| 2350 | workspaceId: installation.workspaceId, | 2350 | workspaceId: installation.scopeId, |
| 2351 | sourceId: driveSource.id, | 2351 | sourceId: driveSource.id, |
| 2352 | }, | 2352 | }, |
| 2353 | }), | 2353 | }), |
| @@ -2357,7 +2357,7 @@ describe("executor-runtime", () => { · 3 unmodified lines | |||
| 2357 | (client) => | 2357 | (client) => |
| 2358 | client.sources.get({ | 2358 | client.sources.get({ |
| 2359 | path: { | 2359 | path: { |
| 2360 | workspaceId: installation.workspaceId, | 2360 | workspaceId: installation.scopeId, |
| 2361 | sourceId: gmailSource.id, | 2361 | sourceId: gmailSource.id, |
| 2362 | }, | 2362 | }, |
| 2363 | }), | 2363 | }), |
| @@ -10,8 +10,8 @@ import type { · 9 unmodified lines | |||
| 10 | ProviderAuthGrant, | 10 | ProviderAuthGrant, |
| 11 | SecretMaterial, | 11 | SecretMaterial, |
| 12 | SourceAuthSession, | 12 | SourceAuthSession, |
| 13 | WorkspaceOauthClient, | 13 | ScopeOauthClient, |
| 14 | WorkspaceSourceOauthClient, | 14 | ScopedSourceOauthClient, |
| 15 | } from "#schema"; | 15 | } from "#schema"; |
| 16 | 16 | ||
| 17 | type SecretMaterialSummary = { | 17 | type SecretMaterialSummary = { |
| @@ -25,28 +25,28 @@ type SecretMaterialSummary = { · 7 unmodified lines | |||
| 25 | 25 | ||
| 26 | export type ExecutorStateStoreShape = { | 26 | export type ExecutorStateStoreShape = { |
| 27 | authArtifacts: { | 27 | authArtifacts: { |
| 28 | listByWorkspaceId: ( | 28 | listByScopeId: ( |
| 29 | workspaceId: AuthArtifact["workspaceId"], | 29 | scopeId: AuthArtifact["scopeId"], |
| 30 | ) => Effect.Effect<readonly AuthArtifact[], Error, never>; | 30 | ) => Effect.Effect<readonly AuthArtifact[], Error, never>; |
| 31 | listByWorkspaceAndSourceId: (input: { | 31 | listByScopeAndSourceId: (input: { |
| 32 | workspaceId: AuthArtifact["workspaceId"]; | 32 | scopeId: AuthArtifact["scopeId"]; |
| 33 | sourceId: AuthArtifact["sourceId"]; | 33 | sourceId: AuthArtifact["sourceId"]; |
| 34 | }) => Effect.Effect<readonly AuthArtifact[], Error, never>; | 34 | }) => Effect.Effect<readonly AuthArtifact[], Error, never>; |
| 35 | getByWorkspaceSourceAndActor: (input: { | 35 | getByScopeSourceAndActor: (input: { |
| 36 | workspaceId: AuthArtifact["workspaceId"]; | 36 | scopeId: AuthArtifact["scopeId"]; |
| 37 | sourceId: AuthArtifact["sourceId"]; | 37 | sourceId: AuthArtifact["sourceId"]; |
| 38 | actorAccountId: AuthArtifact["actorAccountId"]; | 38 | actorScopeId: AuthArtifact["actorScopeId"]; |
| 39 | slot: AuthArtifact["slot"]; | 39 | slot: AuthArtifact["slot"]; |
| 40 | }) => Effect.Effect<import("effect/Option").Option<AuthArtifact>, Error, never>; | 40 | }) => Effect.Effect<import("effect/Option").Option<AuthArtifact>, Error, never>; |
| 41 | upsert: (artifact: AuthArtifact) => Effect.Effect<void, Error, never>; | 41 | upsert: (artifact: AuthArtifact) => Effect.Effect<void, Error, never>; |
| 42 | removeByWorkspaceSourceAndActor: (input: { | 42 | removeByScopeSourceAndActor: (input: { |
| 43 | workspaceId: AuthArtifact["workspaceId"]; | 43 | scopeId: AuthArtifact["scopeId"]; |
| 44 | sourceId: AuthArtifact["sourceId"]; | 44 | sourceId: AuthArtifact["sourceId"]; |
| 45 | actorAccountId: AuthArtifact["actorAccountId"]; | 45 | actorScopeId: AuthArtifact["actorScopeId"]; |
| 46 | slot?: AuthArtifact["slot"]; | 46 | slot?: AuthArtifact["slot"]; |
| 47 | }) => Effect.Effect<boolean, Error, never>; | 47 | }) => Effect.Effect<boolean, Error, never>; |
| 48 | removeByWorkspaceAndSourceId: (input: { | 48 | removeByScopeAndSourceId: (input: { |
| 49 | workspaceId: AuthArtifact["workspaceId"]; | 49 | scopeId: AuthArtifact["scopeId"]; |
| 50 | sourceId: AuthArtifact["sourceId"]; | 50 | sourceId: AuthArtifact["sourceId"]; |
| 51 | }) => Effect.Effect<number, Error, never>; | 51 | }) => Effect.Effect<number, Error, never>; |
| 52 | }; | 52 | }; |
| @@ -61,41 +61,41 @@ export type ExecutorStateStoreShape = { · 8 unmodified lines | |||
| 61 | ) => Effect.Effect<boolean, Error, never>; | 61 | ) => Effect.Effect<boolean, Error, never>; |
| 62 | }; | 62 | }; |
| 63 | sourceOauthClients: { | 63 | sourceOauthClients: { |
| 64 | getByWorkspaceSourceAndProvider: (input: { | 64 | getByScopeSourceAndProvider: (input: { |
| 65 | workspaceId: WorkspaceSourceOauthClient["workspaceId"]; | 65 | scopeId: ScopedSourceOauthClient["scopeId"]; |
| 66 | sourceId: WorkspaceSourceOauthClient["sourceId"]; | 66 | sourceId: ScopedSourceOauthClient["sourceId"]; |
| 67 | providerKey: string; | 67 | providerKey: string; |
| 68 | }) => Effect.Effect< | 68 | }) => Effect.Effect< |
| 69 | import("effect/Option").Option<WorkspaceSourceOauthClient>, | 69 | import("effect/Option").Option<ScopedSourceOauthClient>, |
| 70 | Error, | 70 | Error, |
| 71 | never | 71 | never |
| 72 | >; | 72 | >; |
| 73 | upsert: ( | 73 | upsert: ( |
| 74 | oauthClient: WorkspaceSourceOauthClient, | 74 | oauthClient: ScopedSourceOauthClient, |
| 75 | ) => Effect.Effect<void, Error, never>; | 75 | ) => Effect.Effect<void, Error, never>; |
| 76 | removeByWorkspaceAndSourceId: (input: { | 76 | removeByScopeAndSourceId: (input: { |
| 77 | workspaceId: WorkspaceSourceOauthClient["workspaceId"]; | 77 | scopeId: ScopedSourceOauthClient["scopeId"]; |
| 78 | sourceId: WorkspaceSourceOauthClient["sourceId"]; | 78 | sourceId: ScopedSourceOauthClient["sourceId"]; |
| 79 | }) => Effect.Effect<number, Error, never>; | 79 | }) => Effect.Effect<number, Error, never>; |
| 80 | }; | 80 | }; |
| 81 | workspaceOauthClients: { | 81 | scopeOauthClients: { |
| 82 | listByWorkspaceAndProvider: (input: { | 82 | listByScopeAndProvider: (input: { |
| 83 | workspaceId: WorkspaceOauthClient["workspaceId"]; | 83 | scopeId: ScopeOauthClient["scopeId"]; |
| 84 | providerKey: string; | 84 | providerKey: string; |
| 85 | }) => Effect.Effect<readonly WorkspaceOauthClient[], Error, never>; | 85 | }) => Effect.Effect<readonly ScopeOauthClient[], Error, never>; |
| 86 | getById: ( | 86 | getById: ( |
| 87 | id: WorkspaceOauthClient["id"], | 87 | id: ScopeOauthClient["id"], |
| 88 | ) => Effect.Effect<import("effect/Option").Option<WorkspaceOauthClient>, Error, never>; | 88 | ) => Effect.Effect<import("effect/Option").Option<ScopeOauthClient>, Error, never>; |
| 89 | upsert: (oauthClient: WorkspaceOauthClient) => Effect.Effect<void, Error, never>; | 89 | upsert: (oauthClient: ScopeOauthClient) => Effect.Effect<void, Error, never>; |
| 90 | removeById: (id: WorkspaceOauthClient["id"]) => Effect.Effect<boolean, Error, never>; | 90 | removeById: (id: ScopeOauthClient["id"]) => Effect.Effect<boolean, Error, never>; |
| 91 | }; | 91 | }; |
| 92 | providerAuthGrants: { | 92 | providerAuthGrants: { |
| 93 | listByWorkspaceId: ( | 93 | listByScopeId: ( |
| 94 | workspaceId: ProviderAuthGrant["workspaceId"], | 94 | scopeId: ProviderAuthGrant["scopeId"], |
| 95 | ) => Effect.Effect<readonly ProviderAuthGrant[], Error, never>; | 95 | ) => Effect.Effect<readonly ProviderAuthGrant[], Error, never>; |
| 96 | listByWorkspaceActorAndProvider: (input: { | 96 | listByScopeActorAndProvider: (input: { |
| 97 | workspaceId: ProviderAuthGrant["workspaceId"]; | 97 | scopeId: ProviderAuthGrant["scopeId"]; |
| 98 | actorAccountId: ProviderAuthGrant["actorAccountId"]; | 98 | actorScopeId: ProviderAuthGrant["actorScopeId"]; |
| 99 | providerKey: string; | 99 | providerKey: string; |
| 100 | }) => Effect.Effect<readonly ProviderAuthGrant[], Error, never>; | 100 | }) => Effect.Effect<readonly ProviderAuthGrant[], Error, never>; |
| 101 | getById: ( | 101 | getById: ( |
| @@ -106,8 +106,8 @@ export type ExecutorStateStoreShape = { · 4 unmodified lines | |||
| 106 | }; | 106 | }; |
| 107 | sourceAuthSessions: { | 107 | sourceAuthSessions: { |
| 108 | listAll: () => Effect.Effect<readonly SourceAuthSession[], Error, never>; | 108 | listAll: () => Effect.Effect<readonly SourceAuthSession[], Error, never>; |
| 109 | listByWorkspaceId: ( | 109 | listByScopeId: ( |
| 110 | workspaceId: SourceAuthSession["workspaceId"], | 110 | scopeId: SourceAuthSession["scopeId"], |
| 111 | ) => Effect.Effect<readonly SourceAuthSession[], Error, never>; | 111 | ) => Effect.Effect<readonly SourceAuthSession[], Error, never>; |
| 112 | getById: ( | 112 | getById: ( |
| 113 | id: SourceAuthSession["id"], | 113 | id: SourceAuthSession["id"], |
| @@ -115,10 +115,10 @@ export type ExecutorStateStoreShape = { · 1 unmodified line | |||
| 115 | getByState: ( | 115 | getByState: ( |
| 116 | state: SourceAuthSession["state"], | 116 | state: SourceAuthSession["state"], |
| 117 | ) => Effect.Effect<import("effect/Option").Option<SourceAuthSession>, Error, never>; | 117 | ) => Effect.Effect<import("effect/Option").Option<SourceAuthSession>, Error, never>; |
| 118 | getPendingByWorkspaceSourceAndActor: (input: { | 118 | getPendingByScopeSourceAndActor: (input: { |
| 119 | workspaceId: SourceAuthSession["workspaceId"]; | 119 | scopeId: SourceAuthSession["scopeId"]; |
| 120 | sourceId: SourceAuthSession["sourceId"]; | 120 | sourceId: SourceAuthSession["sourceId"]; |
| 121 | actorAccountId: SourceAuthSession["actorAccountId"]; | 121 | actorScopeId: SourceAuthSession["actorScopeId"]; |
| 122 | credentialSlot?: SourceAuthSession["credentialSlot"]; | 122 | credentialSlot?: SourceAuthSession["credentialSlot"]; |
| 123 | }) => Effect.Effect< | 123 | }) => Effect.Effect< |
| 124 | import("effect/Option").Option<SourceAuthSession>, | 124 | import("effect/Option").Option<SourceAuthSession>, |
| @@ -129,12 +129,12 @@ export type ExecutorStateStoreShape = { · 4 unmodified lines | |||
| 129 | update: ( | 129 | update: ( |
| 130 | id: SourceAuthSession["id"], | 130 | id: SourceAuthSession["id"], |
| 131 | patch: Partial< | 131 | patch: Partial< |
| 132 | Omit<SourceAuthSession, "id" | "workspaceId" | "sourceId" | "createdAt"> | 132 | Omit<SourceAuthSession, "id" | "scopeId" | "sourceId" | "createdAt"> |
| 133 | >, | 133 | >, |
| 134 | ) => Effect.Effect<import("effect/Option").Option<SourceAuthSession>, Error, never>; | 134 | ) => Effect.Effect<import("effect/Option").Option<SourceAuthSession>, Error, never>; |
| 135 | upsert: (session: SourceAuthSession) => Effect.Effect<void, Error, never>; | 135 | upsert: (session: SourceAuthSession) => Effect.Effect<void, Error, never>; |
| 136 | removeByWorkspaceAndSourceId: ( | 136 | removeByScopeAndSourceId: ( |
| 137 | workspaceId: SourceAuthSession["workspaceId"], | 137 | scopeId: SourceAuthSession["scopeId"], |
| 138 | sourceId: SourceAuthSession["sourceId"], | 138 | sourceId: SourceAuthSession["sourceId"], |
| 139 | ) => Effect.Effect<boolean, Error, never>; | 139 | ) => Effect.Effect<boolean, Error, never>; |
| 140 | }; | 140 | }; |
| @@ -158,15 +158,15 @@ export type ExecutorStateStoreShape = { · 17 unmodified lines | |||
| 158 | getById: ( | 158 | getById: ( |
| 159 | executionId: Execution["id"], | 159 | executionId: Execution["id"], |
| 160 | ) => Effect.Effect<import("effect/Option").Option<Execution>, Error, never>; | 160 | ) => Effect.Effect<import("effect/Option").Option<Execution>, Error, never>; |
| 161 | getByWorkspaceAndId: ( | 161 | getByScopeAndId: ( |
| 162 | workspaceId: Execution["workspaceId"], | 162 | scopeId: Execution["scopeId"], |
| 163 | executionId: Execution["id"], | 163 | executionId: Execution["id"], |
| 164 | ) => Effect.Effect<import("effect/Option").Option<Execution>, Error, never>; | 164 | ) => Effect.Effect<import("effect/Option").Option<Execution>, Error, never>; |
| 165 | insert: (execution: Execution) => Effect.Effect<void, Error, never>; | 165 | insert: (execution: Execution) => Effect.Effect<void, Error, never>; |
| 166 | update: ( | 166 | update: ( |
| 167 | executionId: Execution["id"], | 167 | executionId: Execution["id"], |
| 168 | patch: Partial< | 168 | patch: Partial< |
| 169 | Omit<Execution, "id" | "workspaceId" | "createdByAccountId" | "createdAt"> | 169 | Omit<Execution, "id" | "scopeId" | "createdByScopeId" | "createdAt"> |
| 170 | >, | 170 | >, |
| 171 | ) => Effect.Effect<import("effect/Option").Option<Execution>, Error, never>; | 171 | ) => Effect.Effect<import("effect/Option").Option<Execution>, Error, never>; |
| 172 | }; | 172 | }; |
| @@ -3,30 +3,56 @@ import { · 2 unmodified lines | |||
| 3 | makeToolInvokerFromTools, | 3 | makeToolInvokerFromTools, |
| 4 | type ToolMap, | 4 | type ToolMap, |
| 5 | } from "@executor/codemode-core"; | 5 | } from "@executor/codemode-core"; |
| 6 | import { clearAllMcpConnectionPools } from "@executor/source-mcp"; | 6 | import { |
| 7 | import type { LocalInstallation } from "#schema"; | 7 | clearAllMcpConnectionPools, |
| 8 | } from "@executor/source-mcp"; | ||
| 9 | import type { | ||
| 10 | LocalInstallation, | ||
| 11 | } from "#schema"; | ||
| 8 | import * as Effect from "effect/Effect"; | 12 | import * as Effect from "effect/Effect"; |
| 9 | import * as Layer from "effect/Layer"; | 13 | import * as Layer from "effect/Layer"; |
| 10 | import * as ManagedRuntime from "effect/ManagedRuntime"; | 14 | import * as ManagedRuntime from "effect/ManagedRuntime"; |
| 11 | 15 | ||
| 12 | import { RuntimeSourceAuthMaterialLive } from "./auth/source-auth-material"; | 16 | import { |
| 13 | import { RuntimeSourceCatalogStoreLive } from "./catalog/source/runtime"; | 17 | RuntimeSourceAuthMaterialLive, |
| 14 | import { reconcileMissingSourceCatalogArtifacts } from "./catalog/source/reconcile"; | 18 | } from "./auth/source-auth-material"; |
| 15 | import { RuntimeSourceCatalogSyncLive } from "./catalog/source/sync"; | 19 | import { |
| 20 | RuntimeSourceCatalogStoreLive, | ||
| 21 | } from "./catalog/source/runtime"; | ||
| 22 | import { | ||
| 23 | reconcileMissingSourceCatalogArtifacts, | ||
| 24 | } from "./catalog/source/reconcile"; | ||
| 25 | import { | ||
| 26 | RuntimeSourceCatalogSyncLive, | ||
| 27 | } from "./catalog/source/sync"; | ||
| 16 | import { | 28 | import { |
| 17 | SourceTypeDeclarationsRefresherService, | 29 | SourceTypeDeclarationsRefresherService, |
| 18 | type SourceTypeDeclarationsRefresherShape, | 30 | type SourceTypeDeclarationsRefresherShape, |
| 19 | } from "./catalog/source/type-declarations"; | 31 | } from "./catalog/source/type-declarations"; |
| 20 | import { createLiveExecutionManager, LiveExecutionManagerService } from "./execution/live"; | 32 | import { |
| 21 | import { RuntimeExecutionResolverLive } from "./execution/workspace/environment"; | 33 | createLiveExecutionManager, |
| 22 | import type { CreateWorkspaceInternalToolMap, WorkspaceInternalToolContext } from "./execution/workspace/tool-invoker"; | 34 | LiveExecutionManagerService, |
| 23 | import type { LoadedLocalExecutorConfig } from "./workspace-config"; | 35 | } from "./execution/live"; |
| 24 | import type { LocalExecutorConfig } from "#schema"; | 36 | import { |
| 25 | import type { InstanceConfig } from "../local/contracts"; | 37 | RuntimeExecutionResolverLive, |
| 38 | } from "./execution/scope/environment"; | ||
| 39 | import type { | ||
| 40 | CreateScopeInternalToolMap, | ||
| 41 | ScopeInternalToolContext, | ||
| 42 | } from "./execution/scope/tool-invoker"; | ||
| 43 | import type { | ||
| 44 | LoadedLocalExecutorConfig, | ||
| 45 | } from "./scope-config"; | ||
| 26 | import type { | 46 | import type { |
| 27 | ExecutorWorkspaceContext, | 47 | LocalExecutorConfig, |
| 28 | ExecutorWorkspaceDescriptor, | 48 | } from "#schema"; |
| 29 | } from "../workspace"; | 49 | import type { |
| 50 | InstanceConfig, | ||
| 51 | } from "../local/contracts"; | ||
| 52 | import type { | ||
| 53 | ExecutorScopeContext, | ||
| 54 | ExecutorScopeDescriptor, | ||
| 55 | } from "../scope"; | ||
| 30 | import { | 56 | import { |
| 31 | LocalInstanceConfigService, | 57 | LocalInstanceConfigService, |
| 32 | type DeleteSecretMaterial, | 58 | type DeleteSecretMaterial, |
| @@ -37,12 +63,14 @@ import { · 4 unmodified lines | |||
| 37 | SecretMaterialUpdaterService, | 63 | SecretMaterialUpdaterService, |
| 38 | type StoreSecretMaterial, | 64 | type StoreSecretMaterial, |
| 39 | type UpdateSecretMaterial, | 65 | type UpdateSecretMaterial, |
| 40 | } from "./workspace/secret-material-providers"; | 66 | } from "./scope/secret-material-providers"; |
| 41 | import type { LocalSourceArtifact } from "./source-artifacts"; | 67 | import type { |
| 68 | LocalSourceArtifact, | ||
| 69 | } from "./source-artifacts"; | ||
| 42 | import { | 70 | import { |
| 43 | type RuntimeLocalWorkspaceState, | 71 | type RuntimeLocalScopeState, |
| 44 | RuntimeLocalWorkspaceLive, | 72 | RuntimeLocalScopeLive, |
| 45 | } from "./workspace/runtime-context"; | 73 | } from "./scope/runtime-context"; |
| 46 | import { | 74 | import { |
| 47 | type LocalToolRuntime, | 75 | type LocalToolRuntime, |
| 48 | type LocalToolRuntimeLoaderShape, | 76 | type LocalToolRuntimeLoaderShape, |
| @@ -53,14 +81,25 @@ import { · 4 unmodified lines | |||
| 53 | makeLocalStorageLayer, | 81 | makeLocalStorageLayer, |
| 54 | type InstallationStoreShape, | 82 | type InstallationStoreShape, |
| 55 | type SourceArtifactStoreShape, | 83 | type SourceArtifactStoreShape, |
| 56 | type WorkspaceConfigStoreShape, | 84 | type ScopeConfigStoreShape, |
| 57 | type WorkspaceStateStoreShape, | 85 | type ScopeStateStoreShape, |
| 58 | } from "./workspace/storage"; | 86 | } from "./scope/storage"; |
| 59 | import type { LocalWorkspaceState } from "./workspace-state"; | 87 | import type { |
| 60 | import { synchronizeLocalWorkspaceState } from "./workspace/workspace-sync"; | 88 | LocalScopeState, |
| 61 | import { ExecutorStateStore, type ExecutorStateStoreShape } from "./executor-state-store"; | 89 | } from "./scope-state"; |
| 62 | import { RuntimeSourceAuthServiceLive } from "./sources/source-auth-service"; | 90 | import { |
| 63 | import { RuntimeSourceStoreLive } from "./sources/source-store"; | 91 | synchronizeLocalScopeState, |
| 92 | } from "./scope/scope-sync"; | ||
| 93 | import { | ||
| 94 | ExecutorStateStore, | ||
| 95 | type ExecutorStateStoreShape, | ||
| 96 | } from "./executor-state-store"; | ||
| 97 | import { | ||
| 98 | RuntimeSourceAuthServiceLive, | ||
| 99 | } from "./sources/source-auth-service"; | ||
| 100 | import { | ||
| 101 | RuntimeSourceStoreLive, | ||
| 102 | } from "./sources/source-store"; | ||
| 64 | 103 | ||
| 65 | export * from "./execution/state"; | 104 | export * from "./execution/state"; |
| 66 | export * from "./sources/executor-tools"; | 105 | export * from "./sources/executor-tools"; |
| @@ -73,28 +112,28 @@ export * from "./sources/source-credential-interactions"; · 6 unmodified lines | |||
| 73 | export * from "./sources/source-adapters/mcp"; | 112 | export * from "./sources/source-adapters/mcp"; |
| 74 | export * from "./sources/source-store"; | 113 | export * from "./sources/source-store"; |
| 75 | export * from "./executor-state-store"; | 114 | export * from "./executor-state-store"; |
| 76 | export * from "./execution/workspace/environment"; | 115 | export * from "./execution/scope/environment"; |
| 77 | export * from "../sources/inspection"; | 116 | export * from "../sources/inspection"; |
| 78 | export * from "../sources/discovery"; | 117 | export * from "../sources/discovery"; |
| 79 | export * from "./execution/service"; | 118 | export * from "./execution/service"; |
| 80 | export type { | 119 | export type { |
| 81 | CreateWorkspaceInternalToolMap, | 120 | CreateScopeInternalToolMap, |
| 82 | WorkspaceInternalToolContext, | 121 | ScopeInternalToolContext, |
| 83 | } from "./execution/workspace/tool-invoker"; | 122 | } from "./execution/scope/tool-invoker"; |
| 84 | export { | 123 | export { |
| 85 | LocalInstanceConfigService, | 124 | LocalInstanceConfigService, |
| 86 | SecretMaterialDeleterService, | 125 | SecretMaterialDeleterService, |
| 87 | SecretMaterialResolverService, | 126 | SecretMaterialResolverService, |
| 88 | SecretMaterialStorerService, | 127 | SecretMaterialStorerService, |
| 89 | SecretMaterialUpdaterService, | 128 | SecretMaterialUpdaterService, |
| 90 | } from "./workspace/secret-material-providers"; | 129 | } from "./scope/secret-material-providers"; |
| 91 | export type { | 130 | export type { |
| 92 | DeleteSecretMaterial, | 131 | DeleteSecretMaterial, |
| 93 | ResolveInstanceConfig, | 132 | ResolveInstanceConfig, |
| 94 | ResolveSecretMaterial, | 133 | ResolveSecretMaterial, |
| 95 | StoreSecretMaterial, | 134 | StoreSecretMaterial, |
| 96 | UpdateSecretMaterial, | 135 | UpdateSecretMaterial, |
| 97 | } from "./workspace/secret-material-providers"; | 136 | } from "./scope/secret-material-providers"; |
| 98 | export { | 137 | export { |
| 99 | builtInSourceAdapters, | 138 | builtInSourceAdapters, |
| 100 | connectableSourceAdapters, | 139 | connectableSourceAdapters, |
| @@ -112,7 +151,7 @@ export { · 11 unmodified lines | |||
| 112 | 151 | ||
| 113 | export type ExecutorRuntimeOptions = { | 152 | export type ExecutorRuntimeOptions = { |
| 114 | executionResolver?: ResolveExecutionEnvironment; | 153 | executionResolver?: ResolveExecutionEnvironment; |
| 115 | createInternalToolMap?: CreateWorkspaceInternalToolMap; | 154 | createInternalToolMap?: CreateScopeInternalToolMap; |
| 116 | resolveSecretMaterial?: ResolveSecretMaterial; | 155 | resolveSecretMaterial?: ResolveSecretMaterial; |
| 117 | getLocalServerBaseUrl?: () => string | undefined; | 156 | getLocalServerBaseUrl?: () => string | undefined; |
| 118 | }; | 157 | }; |
| @@ -134,18 +173,18 @@ export type BoundInstallationStore = { · 15 unmodified lines | |||
| 134 | getOrProvision: () => Effect.Effect<LocalInstallation, Error, never>; | 173 | getOrProvision: () => Effect.Effect<LocalInstallation, Error, never>; |
| 135 | }; | 174 | }; |
| 136 | 175 | ||
| 137 | export type BoundWorkspaceConfigStore = { | 176 | export type BoundScopeConfigStore = { |
| 138 | load: () => Effect.Effect<LoadedLocalExecutorConfig, Error, never>; | 177 | load: () => Effect.Effect<LoadedLocalExecutorConfig, Error, never>; |
| 139 | writeProject: ( | 178 | writeProject: ( |
| 140 | config: LocalExecutorConfig, | 179 | config: LocalExecutorConfig, |
| 141 | ) => Effect.Effect<void, Error, never>; | 180 | ) => Effect.Effect<void, Error, never>; |
| 142 | resolveRelativePath: WorkspaceConfigStoreShape["resolveRelativePath"]; | 181 | resolveRelativePath: ScopeConfigStoreShape["resolveRelativePath"]; |
| 143 | }; | 182 | }; |
| 144 | 183 | ||
| 145 | export type BoundWorkspaceStateStore = { | 184 | export type BoundScopeStateStore = { |
| 146 | load: () => Effect.Effect<LocalWorkspaceState, Error, never>; | 185 | load: () => Effect.Effect<LocalScopeState, Error, never>; |
| 147 | write: ( | 186 | write: ( |
| 148 | state: LocalWorkspaceState, | 187 | state: LocalScopeState, |
| 149 | ) => Effect.Effect<void, Error, never>; | 188 | ) => Effect.Effect<void, Error, never>; |
| 150 | }; | 189 | }; |
| 151 | 190 | ||
| @@ -181,8 +220,8 @@ export type RuntimeInstanceConfigService = { · 29 unmodified lines | |||
| 181 | 220 | ||
| 182 | export type RuntimeStorageServices = { | 221 | export type RuntimeStorageServices = { |
| 183 | installation: BoundInstallationStore; | 222 | installation: BoundInstallationStore; |
| 184 | workspaceConfig: BoundWorkspaceConfigStore; | 223 | scopeConfig: BoundScopeConfigStore; |
| 185 | workspaceState: BoundWorkspaceStateStore; | 224 | scopeState: BoundScopeStateStore; |
| 186 | sourceArtifacts: BoundSourceArtifactStore; | 225 | sourceArtifacts: BoundSourceArtifactStore; |
| 187 | executorState: ExecutorStateStoreShape; | 226 | executorState: ExecutorStateStoreShape; |
| 188 | secretMaterial: RuntimeSecretMaterialServices; | 227 | secretMaterial: RuntimeSecretMaterialServices; |
| @@ -190,7 +229,7 @@ export type RuntimeStorageServices = { · 1 unmodified line | |||
| 190 | }; | 229 | }; |
| 191 | 230 | ||
| 192 | export type ExecutorRuntimeServices = { | 231 | export type ExecutorRuntimeServices = { |
| 193 | workspace: ExecutorWorkspaceDescriptor; | 232 | scope: ExecutorScopeDescriptor; |
| 194 | storage: RuntimeStorageServices; | 233 | storage: RuntimeStorageServices; |
| 195 | localToolRuntimeLoader?: BoundLocalToolRuntimeLoader; | 234 | localToolRuntimeLoader?: BoundLocalToolRuntimeLoader; |
| 196 | sourceTypeDeclarationsRefresher?: BoundSourceTypeDeclarationsRefresher; | 235 | sourceTypeDeclarationsRefresher?: BoundSourceTypeDeclarationsRefresher; |
| @@ -219,17 +258,17 @@ const toInstallationStoreShape = ( · 22 unmodified lines | |||
| 219 | getOrProvision: input.getOrProvision, | 258 | getOrProvision: input.getOrProvision, |
| 220 | }); | 259 | }); |
| 221 | 260 | ||
| 222 | const toWorkspaceConfigStoreShape = ( | 261 | const toScopeConfigStoreShape = ( |
| 223 | input: BoundWorkspaceConfigStore, | 262 | input: BoundScopeConfigStore, |
| 224 | ): WorkspaceConfigStoreShape => ({ | 263 | ): ScopeConfigStoreShape => ({ |
| 225 | load: input.load, | 264 | load: input.load, |
| 226 | writeProject: ({ config }) => input.writeProject(config), | 265 | writeProject: ({ config }) => input.writeProject(config), |
| 227 | resolveRelativePath: input.resolveRelativePath, | 266 | resolveRelativePath: input.resolveRelativePath, |
| 228 | }); | 267 | }); |
| 229 | 268 | ||
| 230 | const toWorkspaceStateStoreShape = ( | 269 | const toScopeStateStoreShape = ( |
| 231 | input: BoundWorkspaceStateStore, | 270 | input: BoundScopeStateStore, |
| 232 | ): WorkspaceStateStoreShape => ({ | 271 | ): ScopeStateStoreShape => ({ |
| 233 | load: input.load, | 272 | load: input.load, |
| 234 | write: ({ state }) => input.write(state), | 273 | write: ({ state }) => input.write(state), |
| 235 | }); | 274 | }); |
| @@ -256,14 +295,14 @@ const makeInstanceConfigLayer = (input: RuntimeInstanceConfigService) => · 20 unmodified lines | |||
| 256 | 295 | ||
| 257 | export const createExecutorRuntimeLayer = ( | 296 | export const createExecutorRuntimeLayer = ( |
| 258 | input: ExecutorRuntimeOptions & ExecutorRuntimeServices & { | 297 | input: ExecutorRuntimeOptions & ExecutorRuntimeServices & { |
| 259 | localWorkspaceState: RuntimeLocalWorkspaceState; | 298 | localScopeState: RuntimeLocalScopeState; |
| 260 | liveExecutionManager: ReturnType<typeof createLiveExecutionManager>; | 299 | liveExecutionManager: ReturnType<typeof createLiveExecutionManager>; |
| 261 | }, | 300 | }, |
| 262 | ) => { | 301 | ) => { |
| 263 | const storageLayer = makeLocalStorageLayer({ | 302 | const storageLayer = makeLocalStorageLayer({ |
| 264 | installationStore: toInstallationStoreShape(input.storage.installation), | 303 | installationStore: toInstallationStoreShape(input.storage.installation), |
| 265 | workspaceConfigStore: toWorkspaceConfigStoreShape(input.storage.workspaceConfig), | 304 | scopeConfigStore: toScopeConfigStoreShape(input.storage.scopeConfig), |
| 266 | workspaceStateStore: toWorkspaceStateStoreShape(input.storage.workspaceState), | 305 | scopeStateStore: toScopeStateStoreShape(input.storage.scopeState), |
| 267 | sourceArtifactStore: toSourceArtifactStoreShape(input.storage.sourceArtifacts), | 306 | sourceArtifactStore: toSourceArtifactStoreShape(input.storage.sourceArtifacts), |
| 268 | }); | 307 | }); |
| 269 | const localToolRuntimeLayer = Layer.succeed( | 308 | const localToolRuntimeLayer = Layer.succeed( |
| @@ -283,7 +322,7 @@ export const createExecutorRuntimeLayer = ( · 13 unmodified lines | |||
| 283 | 322 | ||
| 284 | const baseLayer = Layer.mergeAll( | 323 | const baseLayer = Layer.mergeAll( |
| 285 | Layer.succeed(ExecutorStateStore, input.storage.executorState), | 324 | Layer.succeed(ExecutorStateStore, input.storage.executorState), |
| 286 | RuntimeLocalWorkspaceLive(input.localWorkspaceState), | 325 | RuntimeLocalScopeLive(input.localScopeState), |
| 287 | storageLayer, | 326 | storageLayer, |
| 288 | Layer.succeed(LiveExecutionManagerService, input.liveExecutionManager), | 327 | Layer.succeed(LiveExecutionManagerService, input.liveExecutionManager), |
| 289 | sourceTypeDeclarationsRefresherLayer, | 328 | sourceTypeDeclarationsRefresherLayer, |
| @@ -381,16 +420,18 @@ export const createExecutorRuntimeFromServices = (input: { · 91 unmodified lines | |||
| 381 | .getOrProvision() | 420 | .getOrProvision() |
| 382 | .pipe(Effect.mapError(toRuntimeBootstrapError)); | 421 | .pipe(Effect.mapError(toRuntimeBootstrapError)); |
| 383 | 422 | ||
| 384 | const loadedLocalConfig = yield* input.services.storage.workspaceConfig | 423 | const loadedLocalConfig = yield* input.services.storage.scopeConfig |
| 385 | .load() | 424 | .load() |
| 386 | .pipe(Effect.mapError(toRuntimeBootstrapError)); | 425 | .pipe(Effect.mapError(toRuntimeBootstrapError)); |
| 387 | 426 | ||
| 388 | const runtimeWorkspace: ExecutorWorkspaceContext = { | 427 | const runtimeWorkspace: ExecutorScopeContext = { |
| 389 | ...input.services.workspace, | 428 | ...input.services.scope, |
| 390 | workspaceId: localInstallation.workspaceId, | 429 | scopeId: localInstallation.scopeId, |
| 391 | accountId: localInstallation.accountId, | 430 | actorScopeId: input.services.scope.actorScopeId ?? localInstallation.actorScopeId, |
| 431 | resolutionScopeIds: | ||
| 432 | input.services.scope.resolutionScopeIds ?? localInstallation.resolutionScopeIds, | ||
| 392 | }; | 433 | }; |
| 393 | const effectiveLocalConfig = yield* synchronizeLocalWorkspaceState({ | 434 | const effectiveLocalConfig = yield* synchronizeLocalScopeState({ |
| 394 | loadedConfig: loadedLocalConfig, | 435 | loadedConfig: loadedLocalConfig, |
| 395 | }) | 436 | }) |
| 396 | .pipe( | 437 | .pipe( |
| @@ -399,11 +440,11 @@ export const createExecutorRuntimeFromServices = (input: { · 2 unmodified lines | |||
| 399 | installationStore: toInstallationStoreShape( | 440 | installationStore: toInstallationStoreShape( |
| 400 | input.services.storage.installation, | 441 | input.services.storage.installation, |
| 401 | ), | 442 | ), |
| 402 | workspaceConfigStore: toWorkspaceConfigStoreShape( | 443 | scopeConfigStore: toScopeConfigStoreShape( |
| 403 | input.services.storage.workspaceConfig, | 444 | input.services.storage.scopeConfig, |
| 404 | ), | 445 | ), |
| 405 | workspaceStateStore: toWorkspaceStateStoreShape( | 446 | scopeStateStore: toScopeStateStoreShape( |
| 406 | input.services.storage.workspaceState, | 447 | input.services.storage.scopeState, |
| 407 | ), | 448 | ), |
| 408 | sourceArtifactStore: toSourceArtifactStoreShape( | 449 | sourceArtifactStore: toSourceArtifactStoreShape( |
| 409 | input.services.storage.sourceArtifacts, | 450 | input.services.storage.sourceArtifacts, |
| @@ -412,12 +453,9 @@ export const createExecutorRuntimeFromServices = (input: { · 2 unmodified lines | |||
| 412 | ), | 453 | ), |
| 413 | ) | 454 | ) |
| 414 | .pipe(Effect.mapError(toRuntimeBootstrapError)); | 455 | .pipe(Effect.mapError(toRuntimeBootstrapError)); |
| 415 | const runtimeLocalWorkspaceState: RuntimeLocalWorkspaceState = { | 456 | const runtimeLocalScopeState: RuntimeLocalScopeState = { |
| 416 | workspace: runtimeWorkspace, | 457 | scope: runtimeWorkspace, |
| 417 | installation: { | 458 | installation: localInstallation, |
| 418 | workspaceId: localInstallation.workspaceId, | ||
| 419 | accountId: localInstallation.accountId, | ||
| 420 | }, | ||
| 421 | loadedConfig: { | 459 | loadedConfig: { |
| 422 | ...loadedLocalConfig, | 460 | ...loadedLocalConfig, |
| 423 | config: effectiveLocalConfig, | 461 | config: effectiveLocalConfig, |
| @@ -428,14 +466,14 @@ export const createExecutorRuntimeFromServices = (input: { · 4 unmodified lines | |||
| 428 | const concreteRuntimeLayer = createExecutorRuntimeLayer({ | 466 | const concreteRuntimeLayer = createExecutorRuntimeLayer({ |
| 429 | ...input, | 467 | ...input, |
| 430 | ...input.services, | 468 | ...input.services, |
| 431 | localWorkspaceState: runtimeLocalWorkspaceState, | 469 | localScopeState: runtimeLocalScopeState, |
| 432 | liveExecutionManager, | 470 | liveExecutionManager, |
| 433 | }); | 471 | }); |
| 434 | const managedRuntime = ManagedRuntime.make(concreteRuntimeLayer); | 472 | const managedRuntime = ManagedRuntime.make(concreteRuntimeLayer); |
| 435 | yield* managedRuntime.runtimeEffect; | 473 | yield* managedRuntime.runtimeEffect; |
| 436 | yield* reconcileMissingSourceCatalogArtifacts({ | 474 | yield* reconcileMissingSourceCatalogArtifacts({ |
| 437 | workspaceId: localInstallation.workspaceId, | 475 | scopeId: localInstallation.scopeId, |
| 438 | actorAccountId: localInstallation.accountId, | 476 | actorScopeId: localInstallation.actorScopeId, |
| 439 | }).pipe( | 477 | }).pipe( |
| 440 | Effect.provide(managedRuntime), | 478 | Effect.provide(managedRuntime), |
| 441 | Effect.catchAll(() => Effect.void), | 479 | Effect.catchAll(() => Effect.void), |
| @@ -1,10 +1,16 @@ | |||
| 1 | import { describe, expect, it } from "@effect/vitest"; | 1 | import { |
| 2 | describe, | ||
| 3 | expect, | ||
| 4 | it, | ||
| 5 | } from "@effect/vitest"; | ||
| 2 | 6 | ||
| 3 | import type { LocalWorkspacePolicy } from "#schema"; | 7 | import type { |
| 8 | LocalScopePolicy, | ||
| 9 | } from "#schema"; | ||
| 4 | import { | 10 | import { |
| 5 | PolicyIdSchema, | 11 | PolicyIdSchema, |
| 6 | SourceIdSchema, | 12 | SourceIdSchema, |
| 7 | WorkspaceIdSchema, | 13 | ScopeIdSchema, |
| 8 | } from "#schema"; | 14 | } from "#schema"; |
| 9 | 15 | ||
| 10 | import { | 16 | import { |
| @@ -12,7 +18,7 @@ import { · 1 unmodified line | |||
| 12 | type InvocationDescriptor, | 18 | type InvocationDescriptor, |
| 13 | } from "./invocation-policy-engine"; | 19 | } from "./invocation-policy-engine"; |
| 14 | 20 | ||
| 15 | const workspaceId = WorkspaceIdSchema.make("ws_policy_engine"); | 21 | const scopeId = ScopeIdSchema.make("ws_policy_engine"); |
| 16 | const sourceId = SourceIdSchema.make("src_policy_engine"); | 22 | const sourceId = SourceIdSchema.make("src_policy_engine"); |
| 17 | 23 | ||
| 18 | const now = 1_700_000_000_000; | 24 | const now = 1_700_000_000_000; |
| @@ -29,11 +35,11 @@ const baseDescriptor: InvocationDescriptor = { · 10 unmodified lines | |||
| 29 | }; | 35 | }; |
| 30 | 36 | ||
| 31 | const basePolicy = ( | 37 | const basePolicy = ( |
| 32 | patch: Partial<LocalWorkspacePolicy> = {}, | 38 | patch: Partial<LocalScopePolicy> = {}, |
| 33 | ): LocalWorkspacePolicy => ({ | 39 | ): LocalScopePolicy => ({ |
| 34 | id: PolicyIdSchema.make(`pol_${Math.random().toString(36).slice(2, 8)}`), | 40 | id: PolicyIdSchema.make(`pol_${Math.random().toString(36).slice(2, 8)}`), |
| 35 | key: "vercel-dns", | 41 | key: "vercel-dns", |
| 36 | workspaceId, | 42 | scopeId, |
| 37 | resourcePattern: "vercel.api.dns.createRecord", | 43 | resourcePattern: "vercel.api.dns.createRecord", |
| 38 | effect: "allow", | 44 | effect: "allow", |
| 39 | approvalMode: "auto", | 45 | approvalMode: "auto", |
| @@ -57,7 +63,7 @@ describe("invocation-policy-engine", () => { · 17 unmodified lines | |||
| 57 | args: {}, | 63 | args: {}, |
| 58 | policies: [], | 64 | policies: [], |
| 59 | context: { | 65 | context: { |
| 60 | workspaceId, | 66 | scopeId, |
| 61 | }, | 67 | }, |
| 62 | }); | 68 | }); |
| 63 | 69 | ||
| @@ -70,7 +76,7 @@ describe("invocation-policy-engine", () => { · 6 unmodified lines | |||
| 70 | args: { domain: "testing.executor.sh" }, | 76 | args: { domain: "testing.executor.sh" }, |
| 71 | policies: [], | 77 | policies: [], |
| 72 | context: { | 78 | context: { |
| 73 | workspaceId, | 79 | scopeId, |
| 74 | }, | 80 | }, |
| 75 | }); | 81 | }); |
| 76 | 82 | ||
| @@ -85,7 +91,7 @@ describe("invocation-policy-engine", () => { · 8 unmodified lines | |||
| 85 | id: PolicyIdSchema.make("pol_allow"), | 91 | id: PolicyIdSchema.make("pol_allow"), |
| 86 | })], | 92 | })], |
| 87 | context: { | 93 | context: { |
| 88 | workspaceId, | 94 | scopeId, |
| 89 | }, | 95 | }, |
| 90 | }); | 96 | }); |
| 91 | 97 | ||
| @@ -113,7 +119,7 @@ describe("invocation-policy-engine", () => { · 21 unmodified lines | |||
| 113 | }), | 119 | }), |
| 114 | ], | 120 | ], |
| 115 | context: { | 121 | context: { |
| 116 | workspaceId, | 122 | scopeId, |
| 117 | }, | 123 | }, |
| 118 | }); | 124 | }); |
| 119 | 125 | ||
| @@ -130,7 +136,7 @@ describe("invocation-policy-engine", () => { · 10 unmodified lines | |||
| 130 | enabled: false, | 136 | enabled: false, |
| 131 | })], | 137 | })], |
| 132 | context: { | 138 | context: { |
| 133 | workspaceId, | 139 | scopeId, |
| 134 | }, | 140 | }, |
| 135 | }); | 141 | }); |
| 136 | 142 | ||
| @@ -1,5 +1,5 @@ | |||
| 1 | import type { | 1 | import type { |
| 2 | LocalWorkspacePolicy, | 2 | LocalScopePolicy, |
| 3 | Source, | 3 | Source, |
| 4 | } from "#schema"; | 4 | } from "#schema"; |
| 5 | 5 | ||
| @@ -22,13 +22,13 @@ export type InvocationDescriptor = { · 16 unmodified lines | |||
| 22 | }; | 22 | }; |
| 23 | 23 | ||
| 24 | export type InvocationPolicyContext = { | 24 | export type InvocationPolicyContext = { |
| 25 | workspaceId: LocalWorkspacePolicy["workspaceId"]; | 25 | scopeId: LocalScopePolicy["scopeId"]; |
| 26 | }; | 26 | }; |
| 27 | 27 | ||
| 28 | export type InvocationAuthorizationDecision = { | 28 | export type InvocationAuthorizationDecision = { |
| 29 | kind: "allow" | "deny" | "require_interaction"; | 29 | kind: "allow" | "deny" | "require_interaction"; |
| 30 | reason: string; | 30 | reason: string; |
| 31 | matchedPolicyId: LocalWorkspacePolicy["id"] | null; | 31 | matchedPolicyId: LocalScopePolicy["id"] | null; |
| 32 | }; | 32 | }; |
| 33 | 33 | ||
| 34 | const matchesGlob = (pattern: string, value: string): boolean => { | 34 | const matchesGlob = (pattern: string, value: string): boolean => { |
| @@ -38,7 +38,7 @@ const matchesGlob = (pattern: string, value: string): boolean => { · 3 unmodified lines | |||
| 38 | return new RegExp(`^${escaped}$`).test(value); | 38 | return new RegExp(`^${escaped}$`).test(value); |
| 39 | }; | 39 | }; |
| 40 | 40 | ||
| 41 | const policySpecificity = (policy: LocalWorkspacePolicy): number => | 41 | const policySpecificity = (policy: LocalScopePolicy): number => |
| 42 | policy.priority + Math.max(1, policy.resourcePattern.replace(/\*/g, "").length); | 42 | policy.priority + Math.max(1, policy.resourcePattern.replace(/\*/g, "").length); |
| 43 | 43 | ||
| 44 | const defaultDecisionForInvocation = ( | 44 | const defaultDecisionForInvocation = ( |
| @@ -60,7 +60,7 @@ const defaultDecisionForInvocation = ( · 15 unmodified lines | |||
| 60 | }; | 60 | }; |
| 61 | 61 | ||
| 62 | const resolvePolicyDecision = ( | 62 | const resolvePolicyDecision = ( |
| 63 | policy: LocalWorkspacePolicy, | 63 | policy: LocalScopePolicy, |
| 64 | ): InvocationAuthorizationDecision => { | 64 | ): InvocationAuthorizationDecision => { |
| 65 | if (policy.effect === "deny") { | 65 | if (policy.effect === "deny") { |
| 66 | return { | 66 | return { |
| @@ -88,13 +88,13 @@ const resolvePolicyDecision = ( · 21 unmodified lines | |||
| 88 | export const evaluateInvocationPolicy = (input: { | 88 | export const evaluateInvocationPolicy = (input: { |
| 89 | descriptor: InvocationDescriptor; | 89 | descriptor: InvocationDescriptor; |
| 90 | args: unknown; | 90 | args: unknown; |
| 91 | policies: ReadonlyArray<LocalWorkspacePolicy>; | 91 | policies: ReadonlyArray<LocalScopePolicy>; |
| 92 | context: InvocationPolicyContext; | 92 | context: InvocationPolicyContext; |
| 93 | }): InvocationAuthorizationDecision => { | 93 | }): InvocationAuthorizationDecision => { |
| 94 | const matchingPolicies = input.policies | 94 | const matchingPolicies = input.policies |
| 95 | .filter((policy) => | 95 | .filter((policy) => |
| 96 | policy.enabled | 96 | policy.enabled |
| 97 | && policy.workspaceId === input.context.workspaceId | 97 | && policy.scopeId === input.context.scopeId |
| 98 | && matchesGlob(policy.resourcePattern, input.descriptor.toolPath)) | 98 | && matchesGlob(policy.resourcePattern, input.descriptor.toolPath)) |
| 99 | .sort((left, right) => | 99 | .sort((left, right) => |
| 100 | policySpecificity(right) - policySpecificity(left) | 100 | policySpecificity(right) - policySpecificity(left) |
| @@ -1,4 +1,6 @@ | |||
| 1 | import type { LocalExecutorConfig } from "#schema"; | 1 | import type { |
| 2 | LocalExecutorConfig, | ||
| 3 | } from "#schema"; | ||
| 2 | 4 | ||
| 3 | export type LoadedExecutorConfig = { | 5 | export type LoadedExecutorConfig = { |
| 4 | config: LocalExecutorConfig | null; | 6 | config: LocalExecutorConfig | null; |
| @@ -1,17 +1,17 @@ | |||
| 1 | import * as Data from "effect/Data"; | 1 | import * as Data from "effect/Data"; |
| 2 | 2 | ||
| 3 | export class RuntimeLocalWorkspaceUnavailableError extends Data.TaggedError( | 3 | export class RuntimeLocalScopeUnavailableError extends Data.TaggedError( |
| 4 | "RuntimeLocalWorkspaceUnavailableError", | 4 | "RuntimeLocalScopeUnavailableError", |
| 5 | )<{ | 5 | )<{ |
| 6 | readonly message: string; | 6 | readonly message: string; |
| 7 | }> {} | 7 | }> {} |
| 8 | 8 | ||
| 9 | export class RuntimeLocalWorkspaceMismatchError extends Data.TaggedError( | 9 | export class RuntimeLocalScopeMismatchError extends Data.TaggedError( |
| 10 | "RuntimeLocalWorkspaceMismatchError", | 10 | "RuntimeLocalScopeMismatchError", |
| 11 | )<{ | 11 | )<{ |
| 12 | readonly message: string; | 12 | readonly message: string; |
| 13 | readonly requestedWorkspaceId: string; | 13 | readonly requestedScopeId: string; |
| 14 | readonly activeWorkspaceId: string; | 14 | readonly activeScopeId: string; |
| 15 | }> {} | 15 | }> {} |
| 16 | 16 | ||
| 17 | export class LocalConfiguredSourceNotFoundError extends Data.TaggedError( | 17 | export class LocalConfiguredSourceNotFoundError extends Data.TaggedError( |
| @@ -13,13 +13,13 @@ const LocalWorkspaceSourceStateSchema = Schema.Struct({ · 12 unmodified lines | |||
| 13 | updatedAt: TimestampMsSchema, | 13 | updatedAt: TimestampMsSchema, |
| 14 | }); | 14 | }); |
| 15 | 15 | ||
| 16 | const LocalWorkspacePolicyStateSchema = Schema.Struct({ | 16 | const LocalScopePolicyStateSchema = Schema.Struct({ |
| 17 | id: PolicyIdSchema, | 17 | id: PolicyIdSchema, |
| 18 | createdAt: TimestampMsSchema, | 18 | createdAt: TimestampMsSchema, |
| 19 | updatedAt: TimestampMsSchema, | 19 | updatedAt: TimestampMsSchema, |
| 20 | }); | 20 | }); |
| 21 | 21 | ||
| 22 | export const LocalWorkspaceStateSchema = Schema.Struct({ | 22 | export const LocalScopeStateSchema = Schema.Struct({ |
| 23 | version: Schema.Literal(1), | 23 | version: Schema.Literal(1), |
| 24 | sources: Schema.Record({ | 24 | sources: Schema.Record({ |
| 25 | key: Schema.String, | 25 | key: Schema.String, |
| @@ -27,15 +27,15 @@ export const LocalWorkspaceStateSchema = Schema.Struct({ · 1 unmodified line | |||
| 27 | }), | 27 | }), |
| 28 | policies: Schema.Record({ | 28 | policies: Schema.Record({ |
| 29 | key: Schema.String, | 29 | key: Schema.String, |
| 30 | value: LocalWorkspacePolicyStateSchema, | 30 | value: LocalScopePolicyStateSchema, |
| 31 | }), | 31 | }), |
| 32 | }); | 32 | }); |
| 33 | 33 | ||
| 34 | export type LocalWorkspaceSourceState = typeof LocalWorkspaceSourceStateSchema.Type; | 34 | export type LocalWorkspaceSourceState = typeof LocalWorkspaceSourceStateSchema.Type; |
| 35 | export type LocalWorkspacePolicyState = typeof LocalWorkspacePolicyStateSchema.Type; | 35 | export type LocalScopePolicyState = typeof LocalScopePolicyStateSchema.Type; |
| 36 | export type LocalWorkspaceState = typeof LocalWorkspaceStateSchema.Type; | 36 | export type LocalScopeState = typeof LocalScopeStateSchema.Type; |
| 37 | 37 | ||
| 38 | export const defaultLocalWorkspaceState = (): LocalWorkspaceState => ({ | 38 | export const defaultLocalScopeState = (): LocalScopeState => ({ |
| 39 | version: 1, | 39 | version: 1, |
| 40 | sources: {}, | 40 | sources: {}, |
| 41 | policies: {}, | 41 | policies: {}, |
File renamed without changes.
| @@ -0,0 +1,85 @@ | |||
| 1 | import * as Context from "effect/Context"; | ||
| 2 | import * as Effect from "effect/Effect"; | ||
| 3 | import * as Layer from "effect/Layer"; | ||
| 4 | import * as Option from "effect/Option"; | ||
| 5 | |||
| 6 | import type { | ||
| 7 | ScopeId, | ||
| 8 | } from "#schema"; | ||
| 9 | import type { | ||
| 10 | ExecutorScopeContext, | ||
| 11 | } from "../../scope"; | ||
| 12 | import type { | ||
| 13 | LoadedLocalExecutorConfig, | ||
| 14 | } from "../scope-config"; | ||
| 15 | import { | ||
| 16 | RuntimeLocalScopeMismatchError, | ||
| 17 | RuntimeLocalScopeUnavailableError, | ||
| 18 | } from "../scope-errors"; | ||
| 19 | |||
| 20 | export type RuntimeLocalScopeState = { | ||
| 21 | scope: ExecutorScopeContext; | ||
| 22 | installation: { | ||
| 23 | scopeId: ScopeId; | ||
| 24 | actorScopeId: ScopeId; | ||
| 25 | resolutionScopeIds: ReadonlyArray<ScopeId>; | ||
| 26 | }; | ||
| 27 | loadedConfig: LoadedLocalExecutorConfig; | ||
| 28 | }; | ||
| 29 | |||
| 30 | export class RuntimeLocalScopeService extends Context.Tag( | ||
| 31 | "#runtime/RuntimeLocalScopeService", | ||
| 32 | )<RuntimeLocalScopeService, RuntimeLocalScopeState>() {} | ||
| 33 | |||
| 34 | export const RuntimeLocalScopeLive = ( | ||
| 35 | runtimeLocalScope: RuntimeLocalScopeState, | ||
| 36 | ) => Layer.succeed(RuntimeLocalScopeService, runtimeLocalScope); | ||
| 37 | |||
| 38 | export const provideOptionalRuntimeLocalScope = <A, E, R>( | ||
| 39 | effect: Effect.Effect<A, E, R>, | ||
| 40 | runtimeLocalScope: RuntimeLocalScopeState | null | undefined, | ||
| 41 | ): Effect.Effect<A, E, R> => | ||
| 42 | runtimeLocalScope === null || runtimeLocalScope === undefined | ||
| 43 | ? effect | ||
| 44 | : effect.pipe(Effect.provide(RuntimeLocalScopeLive(runtimeLocalScope))); | ||
| 45 | |||
| 46 | export const getRuntimeLocalScopeOption = () => | ||
| 47 | Effect.contextWith((context) => | ||
| 48 | Context.getOption(context, RuntimeLocalScopeService), | ||
| 49 | ).pipe( | ||
| 50 | Effect.map((option) => (Option.isSome(option) ? option.value : null)), | ||
| 51 | ) as Effect.Effect<RuntimeLocalScopeState | null, never, never>; | ||
| 52 | |||
| 53 | export const requireRuntimeLocalScope = ( | ||
| 54 | scopeId?: ScopeId, | ||
| 55 | ): Effect.Effect< | ||
| 56 | RuntimeLocalScopeState, | ||
| 57 | RuntimeLocalScopeUnavailableError | RuntimeLocalScopeMismatchError, | ||
| 58 | never | ||
| 59 | > => | ||
| 60 | Effect.gen(function* () { | ||
| 61 | const runtimeLocalScope = yield* getRuntimeLocalScopeOption(); | ||
| 62 | if (runtimeLocalScope === null) { | ||
| 63 | return yield* new RuntimeLocalScopeUnavailableError({ | ||
| 64 | message: "Runtime local scope is unavailable", | ||
| 65 | }); | ||
| 66 | } | ||
| 67 | |||
| 68 | if ( | ||
| 69 | scopeId !== undefined | ||
| 70 | && runtimeLocalScope.installation.scopeId !== scopeId | ||
| 71 | ) { | ||
| 72 | return yield* new RuntimeLocalScopeMismatchError({ | ||
| 73 | message: `Scope ${scopeId} is not the active local scope ${runtimeLocalScope.installation.scopeId}`, | ||
| 74 | requestedScopeId: scopeId, | ||
| 75 | activeScopeId: runtimeLocalScope.installation.scopeId, | ||
| 76 | }); | ||
| 77 | } | ||
| 78 | |||
| 79 | return runtimeLocalScope; | ||
| 80 | }); | ||
| 81 | |||
| 82 | export const requireRuntimeLocalActorScopeId = (scopeId?: ScopeId) => | ||
| 83 | requireRuntimeLocalScope(scopeId).pipe( | ||
| 84 | Effect.map((runtimeLocalScope) => runtimeLocalScope.installation.actorScopeId), | ||
| 85 | ); | ||
| @@ -1,8 +1,14 @@ | |||
| 1 | import * as Effect from "effect/Effect"; | 1 | import * as Effect from "effect/Effect"; |
| 2 | 2 | ||
| 3 | import { type LoadedLocalExecutorConfig } from "../workspace-config"; | 3 | import { |
| 4 | import { WorkspaceStateStore } from "./storage"; | 4 | type LoadedLocalExecutorConfig, |
| 5 | import { type LocalWorkspaceState } from "../workspace-state"; | 5 | } from "../scope-config"; |
| 6 | import { | ||
| 7 | ScopeStateStore, | ||
| 8 | } from "./storage"; | ||
| 9 | import { | ||
| 10 | type LocalScopeState, | ||
| 11 | } from "../scope-state"; | ||
| 6 | 12 | ||
| 7 | const trimOrNull = (value: string | null | undefined): string | null => { | 13 | const trimOrNull = (value: string | null | undefined): string | null => { |
| 8 | if (value == null) { | 14 | if (value == null) { |
| @@ -35,10 +41,10 @@ export const derivePolicyConfigKey = ( · 26 unmodified lines | |||
| 35 | 41 | ||
| 36 | const pruneLocalWorkspaceState = (input: { | 42 | const pruneLocalWorkspaceState = (input: { |
| 37 | loadedConfig: LoadedLocalExecutorConfig; | 43 | loadedConfig: LoadedLocalExecutorConfig; |
| 38 | }): Effect.Effect<LocalWorkspaceState, Error, WorkspaceStateStore> => | 44 | }): Effect.Effect<LocalScopeState, Error, ScopeStateStore> => |
| 39 | Effect.gen(function* () { | 45 | Effect.gen(function* () { |
| 40 | const workspaceStateStore = yield* WorkspaceStateStore; | 46 | const scopeStateStore = yield* ScopeStateStore; |
| 41 | const currentState = yield* workspaceStateStore.load(); | 47 | const currentState = yield* scopeStateStore.load(); |
| 42 | 48 | ||
| 43 | const configuredSourceIds = new Set( | 49 | const configuredSourceIds = new Set( |
| 44 | Object.keys(input.loadedConfig.config?.sources ?? {}), | 50 | Object.keys(input.loadedConfig.config?.sources ?? {}), |
| @@ -47,7 +53,7 @@ const pruneLocalWorkspaceState = (input: { · 2 unmodified lines | |||
| 47 | Object.keys(input.loadedConfig.config?.policies ?? {}), | 53 | Object.keys(input.loadedConfig.config?.policies ?? {}), |
| 48 | ); | 54 | ); |
| 49 | 55 | ||
| 50 | const nextState: LocalWorkspaceState = { | 56 | const nextState: LocalScopeState = { |
| 51 | ...currentState, | 57 | ...currentState, |
| 52 | sources: Object.fromEntries( | 58 | sources: Object.fromEntries( |
| 53 | Object.entries(currentState.sources).filter(([sourceId]) => | 59 | Object.entries(currentState.sources).filter(([sourceId]) => |
| @@ -65,16 +71,16 @@ const pruneLocalWorkspaceState = (input: { · 11 unmodified lines | |||
| 65 | return currentState; | 71 | return currentState; |
| 66 | } | 72 | } |
| 67 | 73 | ||
| 68 | yield* workspaceStateStore.write({ | 74 | yield* scopeStateStore.write({ |
| 69 | state: nextState, | 75 | state: nextState, |
| 70 | }); | 76 | }); |
| 71 | 77 | ||
| 72 | return nextState; | 78 | return nextState; |
| 73 | }); | 79 | }); |
| 74 | 80 | ||
| 75 | export const synchronizeLocalWorkspaceState = (input: { | 81 | export const synchronizeLocalScopeState = (input: { |
| 76 | loadedConfig: LoadedLocalExecutorConfig; | 82 | loadedConfig: LoadedLocalExecutorConfig; |
| 77 | }): Effect.Effect<LoadedLocalExecutorConfig["config"], Error, WorkspaceStateStore> => | 83 | }): Effect.Effect<LoadedLocalExecutorConfig["config"], Error, ScopeStateStore> => |
| 78 | Effect.gen(function* () { | 84 | Effect.gen(function* () { |
| 79 | yield* pruneLocalWorkspaceState({ | 85 | yield* pruneLocalWorkspaceState({ |
| 80 | loadedConfig: input.loadedConfig, | 86 | loadedConfig: input.loadedConfig, |
| @@ -1,4 +1,6 @@ | |||
| 1 | import type { InstanceConfig } from "../../local/contracts"; | 1 | import type { |
| 2 | InstanceConfig, | ||
| 3 | } from "../../local/contracts"; | ||
| 2 | import * as Context from "effect/Context"; | 4 | import * as Context from "effect/Context"; |
| 3 | import * as Effect from "effect/Effect"; | 5 | import * as Effect from "effect/Effect"; |
| 4 | 6 | ||
| @@ -1,12 +1,25 @@ | |||
| 1 | import type { LocalInstallation, LocalExecutorConfig } from "#schema"; | 1 | import type { |
| 2 | LocalInstallation, | ||
| 3 | LocalExecutorConfig, | ||
| 4 | } from "#schema"; | ||
| 2 | import * as Context from "effect/Context"; | 5 | import * as Context from "effect/Context"; |
| 3 | import * as Layer from "effect/Layer"; | 6 | import * as Layer from "effect/Layer"; |
| 4 | 7 | ||
| 5 | import type { LoadedLocalExecutorConfig } from "../workspace-config"; | 8 | import type { |
| 6 | import type { LocalSourceArtifact } from "../source-artifacts"; | 9 | LoadedLocalExecutorConfig, |
| 7 | import type { LocalWorkspaceState } from "../workspace-state"; | 10 | } from "../scope-config"; |
| 8 | import type { SourceCatalogSyncResult } from "@executor/source-core"; | 11 | import type { |
| 9 | import type { Source } from "#schema"; | 12 | LocalSourceArtifact, |
| 13 | } from "../source-artifacts"; | ||
| 14 | import type { | ||
| 15 | LocalScopeState, | ||
| 16 | } from "../scope-state"; | ||
| 17 | import type { | ||
| 18 | SourceCatalogSyncResult, | ||
| 19 | } from "@executor/source-core"; | ||
| 20 | import type { | ||
| 21 | Source, | ||
| 22 | } from "#schema"; | ||
| 10 | 23 | ||
| 11 | export type InstallationStoreShape = { | 24 | export type InstallationStoreShape = { |
| 12 | load: () => import("effect/Effect").Effect<LocalInstallation, Error, never>; | 25 | load: () => import("effect/Effect").Effect<LocalInstallation, Error, never>; |
| @@ -17,28 +30,28 @@ export class InstallationStore extends Context.Tag( · 4 unmodified lines | |||
| 17 | "#runtime/InstallationStore", | 30 | "#runtime/InstallationStore", |
| 18 | )<InstallationStore, InstallationStoreShape>() {} | 31 | )<InstallationStore, InstallationStoreShape>() {} |
| 19 | 32 | ||
| 20 | export type WorkspaceConfigStoreShape = { | 33 | export type ScopeConfigStoreShape = { |
| 21 | load: () => import("effect/Effect").Effect<LoadedLocalExecutorConfig, Error, never>; | 34 | load: () => import("effect/Effect").Effect<LoadedLocalExecutorConfig, Error, never>; |
| 22 | writeProject: (input: { | 35 | writeProject: (input: { |
| 23 | config: LocalExecutorConfig; | 36 | config: LocalExecutorConfig; |
| 24 | }) => import("effect/Effect").Effect<void, Error, never>; | 37 | }) => import("effect/Effect").Effect<void, Error, never>; |
| 25 | resolveRelativePath: (input: { path: string; workspaceRoot: string }) => string; | 38 | resolveRelativePath: (input: { path: string; scopeRoot: string }) => string; |
| 26 | }; | 39 | }; |
| 27 | 40 | ||
| 28 | export class WorkspaceConfigStore extends Context.Tag( | 41 | export class ScopeConfigStore extends Context.Tag( |
| 29 | "#runtime/WorkspaceConfigStore", | 42 | "#runtime/ScopeConfigStore", |
| 30 | )<WorkspaceConfigStore, WorkspaceConfigStoreShape>() {} | 43 | )<ScopeConfigStore, ScopeConfigStoreShape>() {} |
| 31 | 44 | ||
| 32 | export type WorkspaceStateStoreShape = { | 45 | export type ScopeStateStoreShape = { |
| 33 | load: () => import("effect/Effect").Effect<LocalWorkspaceState, Error, never>; | 46 | load: () => import("effect/Effect").Effect<LocalScopeState, Error, never>; |
| 34 | write: (input: { | 47 | write: (input: { |
| 35 | state: LocalWorkspaceState; | 48 | state: LocalScopeState; |
| 36 | }) => import("effect/Effect").Effect<void, Error, never>; | 49 | }) => import("effect/Effect").Effect<void, Error, never>; |
| 37 | }; | 50 | }; |
| 38 | 51 | ||
| 39 | export class WorkspaceStateStore extends Context.Tag( | 52 | export class ScopeStateStore extends Context.Tag( |
| 40 | "#runtime/WorkspaceStateStore", | 53 | "#runtime/ScopeStateStore", |
| 41 | )<WorkspaceStateStore, WorkspaceStateStoreShape>() {} | 54 | )<ScopeStateStore, ScopeStateStoreShape>() {} |
| 42 | 55 | ||
| 43 | export type SourceArtifactStoreShape = { | 56 | export type SourceArtifactStoreShape = { |
| 44 | build: (input: { | 57 | build: (input: { |
| @@ -63,33 +76,33 @@ export class SourceArtifactStore extends Context.Tag( · 18 unmodified lines | |||
| 63 | 76 | ||
| 64 | export type LocalStorageServices = | 77 | export type LocalStorageServices = |
| 65 | | InstallationStore | 78 | | InstallationStore |
| 66 | | WorkspaceConfigStore | 79 | | ScopeConfigStore |
| 67 | | WorkspaceStateStore | 80 | | ScopeStateStore |
| 68 | | SourceArtifactStore; | 81 | | SourceArtifactStore; |
| 69 | 82 | ||
| 70 | export type WorkspaceStorageServices = | 83 | export type ScopeStorageServices = |
| 71 | | WorkspaceConfigStore | 84 | | ScopeConfigStore |
| 72 | | WorkspaceStateStore | 85 | | ScopeStateStore |
| 73 | | SourceArtifactStore; | 86 | | SourceArtifactStore; |
| 74 | 87 | ||
| 75 | export const makeWorkspaceStorageLayer = (input: { | 88 | export const makeScopeStorageLayer = (input: { |
| 76 | workspaceConfigStore: WorkspaceConfigStoreShape; | 89 | scopeConfigStore: ScopeConfigStoreShape; |
| 77 | workspaceStateStore: WorkspaceStateStoreShape; | 90 | scopeStateStore: ScopeStateStoreShape; |
| 78 | sourceArtifactStore: SourceArtifactStoreShape; | 91 | sourceArtifactStore: SourceArtifactStoreShape; |
| 79 | }) => | 92 | }) => |
| 80 | Layer.mergeAll( | 93 | Layer.mergeAll( |
| 81 | Layer.succeed(WorkspaceConfigStore, input.workspaceConfigStore), | 94 | Layer.succeed(ScopeConfigStore, input.scopeConfigStore), |
| 82 | Layer.succeed(WorkspaceStateStore, input.workspaceStateStore), | 95 | Layer.succeed(ScopeStateStore, input.scopeStateStore), |
| 83 | Layer.succeed(SourceArtifactStore, input.sourceArtifactStore), | 96 | Layer.succeed(SourceArtifactStore, input.sourceArtifactStore), |
| 84 | ); | 97 | ); |
| 85 | 98 | ||
| 86 | export const makeLocalStorageLayer = (input: { | 99 | export const makeLocalStorageLayer = (input: { |
| 87 | installationStore: InstallationStoreShape; | 100 | installationStore: InstallationStoreShape; |
| 88 | workspaceConfigStore: WorkspaceConfigStoreShape; | 101 | scopeConfigStore: ScopeConfigStoreShape; |
| 89 | workspaceStateStore: WorkspaceStateStoreShape; | 102 | scopeStateStore: ScopeStateStoreShape; |
| 90 | sourceArtifactStore: SourceArtifactStoreShape; | 103 | sourceArtifactStore: SourceArtifactStoreShape; |
| 91 | }) => | 104 | }) => |
| 92 | Layer.mergeAll( | 105 | Layer.mergeAll( |
| 93 | Layer.succeed(InstallationStore, input.installationStore), | 106 | Layer.succeed(InstallationStore, input.installationStore), |
| 94 | makeWorkspaceStorageLayer(input), | 107 | makeScopeStorageLayer(input), |
| 95 | ); | 108 | ); |
| @@ -9,7 +9,9 @@ import { · 8 unmodified lines | |||
| 9 | import * as Option from "effect/Option"; | 9 | import * as Option from "effect/Option"; |
| 10 | import * as Schema from "effect/Schema"; | 10 | import * as Schema from "effect/Schema"; |
| 11 | 11 | ||
| 12 | import { decodeCatalogSnapshotV1 } from "@executor/ir/catalog"; | 12 | import { |
| 13 | decodeCatalogSnapshotV1, | ||
| 14 | } from "@executor/ir/catalog"; | ||
| 13 | import { | 15 | import { |
| 14 | CatalogSnapshotV1Schema, | 16 | CatalogSnapshotV1Schema, |
| 15 | type CatalogSnapshotV1, | 17 | type CatalogSnapshotV1, |
| @@ -8,45 +8,50 @@ import { · 7 unmodified lines | |||
| 8 | type ToolPath, | 8 | type ToolPath, |
| 9 | } from "@executor/codemode-core"; | 9 | } from "@executor/codemode-core"; |
| 10 | import { | 10 | import { |
| 11 | type AccountId, | 11 | type ScopeId, |
| 12 | ExecutionIdSchema, | 12 | ExecutionIdSchema, |
| 13 | ExecutionInteractionIdSchema, | 13 | ExecutionInteractionIdSchema, |
| 14 | SourceSchema, | 14 | SourceSchema, |
| 15 | type Source, | 15 | type Source, |
| 16 | type WorkspaceId, | ||
| 17 | } from "#schema"; | 16 | } from "#schema"; |
| 18 | import * as Effect from "effect/Effect"; | 17 | import * as Effect from "effect/Effect"; |
| 19 | import * as Cause from "effect/Cause"; | 18 | import * as Cause from "effect/Cause"; |
| 20 | import * as Exit from "effect/Exit"; | 19 | import * as Exit from "effect/Exit"; |
| 21 | import * as Schema from "effect/Schema"; | 20 | import * as Schema from "effect/Schema"; |
| 22 | import type { RuntimeLocalWorkspaceState } from "../workspace/runtime-context"; | 21 | import type { |
| 22 | RuntimeLocalScopeState, | ||
| 23 | } from "../scope/runtime-context"; | ||
| 23 | import { | 24 | import { |
| 24 | type LocalStorageServices, | 25 | type LocalStorageServices, |
| 25 | type InstallationStoreShape, | 26 | type InstallationStoreShape, |
| 26 | type SourceArtifactStoreShape, | 27 | type SourceArtifactStoreShape, |
| 27 | type WorkspaceConfigStoreShape, | 28 | type ScopeConfigStoreShape, |
| 28 | type WorkspaceStateStoreShape, | 29 | type ScopeStateStoreShape, |
| 29 | makeLocalStorageLayer, | 30 | makeLocalStorageLayer, |
| 30 | } from "../workspace/storage"; | 31 | } from "../scope/storage"; |
| 31 | import { provideOptionalRuntimeLocalWorkspace } from "../workspace/runtime-context"; | 32 | import { |
| 32 | import { runtimeEffectError } from "../effect-errors"; | 33 | provideOptionalRuntimeLocalScope, |
| 34 | } from "../scope/runtime-context"; | ||
| 35 | import { | ||
| 36 | runtimeEffectError, | ||
| 37 | } from "../effect-errors"; | ||
| 33 | 38 | ||
| 34 | /** Run an Effect as a Promise, preserving the original error (not FiberFailure). */ | 39 | /** Run an Effect as a Promise, preserving the original error (not FiberFailure). */ |
| 35 | const runEffect = async <A>( | 40 | const runEffect = async <A>( |
| 36 | effect: Effect.Effect<A, unknown, LocalStorageServices>, | 41 | effect: Effect.Effect<A, unknown, LocalStorageServices>, |
| 37 | storage: { | 42 | storage: { |
| 38 | installationStore: InstallationStoreShape; | 43 | installationStore: InstallationStoreShape; |
| 39 | workspaceConfigStore: WorkspaceConfigStoreShape; | 44 | scopeConfigStore: ScopeConfigStoreShape; |
| 40 | workspaceStateStore: WorkspaceStateStoreShape; | 45 | scopeStateStore: ScopeStateStoreShape; |
| 41 | sourceArtifactStore: SourceArtifactStoreShape; | 46 | sourceArtifactStore: SourceArtifactStoreShape; |
| 42 | }, | 47 | }, |
| 43 | runtimeLocalWorkspace: RuntimeLocalWorkspaceState | null = null, | 48 | runtimeLocalScope: RuntimeLocalScopeState | null = null, |
| 44 | ): Promise<A> => { | 49 | ): Promise<A> => { |
| 45 | const baseLayer = makeLocalStorageLayer(storage); | 50 | const baseLayer = makeLocalStorageLayer(storage); |
| 46 | const exit = await Effect.runPromiseExit( | 51 | const exit = await Effect.runPromiseExit( |
| 47 | provideOptionalRuntimeLocalWorkspace( | 52 | provideOptionalRuntimeLocalScope( |
| 48 | effect.pipe(Effect.provide(baseLayer)), | 53 | effect.pipe(Effect.provide(baseLayer)), |
| 49 | runtimeLocalWorkspace, | 54 | runtimeLocalScope, |
| 50 | ), | 55 | ), |
| 51 | ); | 56 | ); |
| 52 | if (Exit.isSuccess(exit)) return exit.value; | 57 | if (Exit.isSuccess(exit)) return exit.value; |
| @@ -69,7 +74,9 @@ import { · 16 unmodified lines | |||
| 69 | executorAddableSourceAdapters, | 74 | executorAddableSourceAdapters, |
| 70 | sourceAdapterRequiresInteractiveConnect, | 75 | sourceAdapterRequiresInteractiveConnect, |
| 71 | } from "./source-adapters"; | 76 | } from "./source-adapters"; |
| 72 | import { decodeSourceCredentialSelectionContent } from "./source-credential-interactions"; | 77 | import { |
| 78 | decodeSourceCredentialSelectionContent, | ||
| 79 | } from "./source-credential-interactions"; | ||
| 73 | 80 | ||
| 74 | const ExecutorSourcesAddInputSchema = Schema.standardSchemaV1( | 81 | const ExecutorSourcesAddInputSchema = Schema.standardSchemaV1( |
| 75 | ExecutorAddSourceInputSchema, | 82 | ExecutorAddSourceInputSchema, |
| @@ -112,7 +119,7 @@ export const EXECUTOR_SOURCES_ADD_HELP_LINES = [ · 36 unmodified lines | |||
| 112 | 119 | ||
| 113 | export const buildExecutorSourcesAddDescription = (): string => | 120 | export const buildExecutorSourcesAddDescription = (): string => |
| 114 | [ | 121 | [ |
| 115 | "Add an MCP, OpenAPI, or GraphQL source to the current workspace.", | 122 | "Add an MCP, OpenAPI, or GraphQL source to the current scope.", |
| 116 | ...EXECUTOR_SOURCES_ADD_HELP_LINES, | 123 | ...EXECUTOR_SOURCES_ADD_HELP_LINES, |
| 117 | ].join("\n"); | 124 | ].join("\n"); |
| 118 | 125 | ||
| @@ -130,29 +137,29 @@ const toSerializableValue = <A>(value: A): A => · 11 unmodified lines | |||
| 130 | JSON.parse(JSON.stringify(value)) as A; | 137 | JSON.parse(JSON.stringify(value)) as A; |
| 131 | 138 | ||
| 132 | type ExecutorSourcesAddToolArgs = | 139 | type ExecutorSourcesAddToolArgs = |
| 133 | | Omit<ExecutorMcpSourceInput, "workspaceId" | "actorAccountId" | "executionId" | "interactionId"> | 140 | | Omit<ExecutorMcpSourceInput, "scopeId" | "actorScopeId" | "executionId" | "interactionId"> |
| 134 | | Omit< | 141 | | Omit< |
| 135 | ExecutorCredentialManagedSourceInput, | 142 | ExecutorCredentialManagedSourceInput, |
| 136 | "workspaceId" | "actorAccountId" | "executionId" | "interactionId" | 143 | "scopeId" | "actorScopeId" | "executionId" | "interactionId" |
| 137 | >; | 144 | >; |
| 138 | 145 | ||
| 139 | type ExecutorGoogleDiscoveryToolArgs = Omit< | 146 | type ExecutorGoogleDiscoveryToolArgs = Omit< |
| 140 | Extract<ExecutorCredentialManagedSourceInput, { service: string; version: string }>, | 147 | Extract<ExecutorCredentialManagedSourceInput, { service: string; version: string }>, |
| 141 | "workspaceId" | "actorAccountId" | "executionId" | "interactionId" | 148 | "scopeId" | "actorScopeId" | "executionId" | "interactionId" |
| 142 | >; | 149 | >; |
| 143 | 150 | ||
| 144 | type ExecutorOpenApiToolArgs = Omit< | 151 | type ExecutorOpenApiToolArgs = Omit< |
| 145 | Extract<ExecutorCredentialManagedSourceInput, { specUrl: string }>, | 152 | Extract<ExecutorCredentialManagedSourceInput, { specUrl: string }>, |
| 146 | "workspaceId" | "actorAccountId" | "executionId" | "interactionId" | 153 | "scopeId" | "actorScopeId" | "executionId" | "interactionId" |
| 147 | >; | 154 | >; |
| 148 | 155 | ||
| 149 | type ExecutorGraphqlToolArgs = Omit< | 156 | type ExecutorGraphqlToolArgs = Omit< |
| 150 | Extract<ExecutorCredentialManagedSourceInput, { kind: "graphql" }>, | 157 | Extract<ExecutorCredentialManagedSourceInput, { kind: "graphql" }>, |
| 151 | "workspaceId" | "actorAccountId" | "executionId" | "interactionId" | 158 | "scopeId" | "actorScopeId" | "executionId" | "interactionId" |
| 152 | >; | 159 | >; |
| 153 | 160 | ||
| 154 | type ExecutorCredentialPromptArgs = { | 161 | type ExecutorCredentialPromptArgs = { |
| 155 | workspaceId: WorkspaceId; | 162 | scopeId: ScopeId; |
| 156 | sourceId: Source["id"]; | 163 | sourceId: Source["id"]; |
| 157 | kind: ExecutorCredentialManagedSourceInput["kind"]; | 164 | kind: ExecutorCredentialManagedSourceInput["kind"]; |
| 158 | endpoint?: string; | 165 | endpoint?: string; |
| @@ -166,7 +173,7 @@ type ExecutorCredentialPromptArgs = { · 7 unmodified lines | |||
| 166 | 173 | ||
| 167 | const isExecutorMcpToolArgs = ( | 174 | const isExecutorMcpToolArgs = ( |
| 168 | args: ExecutorSourcesAddToolArgs, | 175 | args: ExecutorSourcesAddToolArgs, |
| 169 | ): args is Omit<ExecutorMcpSourceInput, "workspaceId" | "actorAccountId" | "executionId" | "interactionId"> => | 176 | ): args is Omit<ExecutorMcpSourceInput, "scopeId" | "actorScopeId" | "executionId" | "interactionId"> => |
| 170 | args.kind === undefined || sourceAdapterRequiresInteractiveConnect(args.kind); | 177 | args.kind === undefined || sourceAdapterRequiresInteractiveConnect(args.kind); |
| 171 | 178 | ||
| 172 | const isExecutorCredentialManagedSourceInput = ( | 179 | const isExecutorCredentialManagedSourceInput = ( |
| @@ -176,8 +183,8 @@ const isExecutorCredentialManagedSourceInput = ( · 3 unmodified lines | |||
| 176 | 183 | ||
| 177 | const prepareExecutorAddSourceInput = (input: { | 184 | const prepareExecutorAddSourceInput = (input: { |
| 178 | args: ExecutorSourcesAddToolArgs; | 185 | args: ExecutorSourcesAddToolArgs; |
| 179 | workspaceId: WorkspaceId; | 186 | scopeId: ScopeId; |
| 180 | accountId: AccountId; | 187 | actorScopeId: ScopeId; |
| 181 | executionId: ReturnType<typeof toExecutionId>; | 188 | executionId: ReturnType<typeof toExecutionId>; |
| 182 | interactionId: ReturnType<typeof ExecutionInteractionIdSchema.make>; | 189 | interactionId: ReturnType<typeof ExecutionInteractionIdSchema.make>; |
| 183 | }): ExecutorAddSourceInput => { | 190 | }): ExecutorAddSourceInput => { |
| @@ -194,8 +201,8 @@ const prepareExecutorAddSourceInput = (input: { · 10 unmodified lines | |||
| 194 | args: input.args.args ?? null, | 201 | args: input.args.args ?? null, |
| 195 | env: input.args.env ?? null, | 202 | env: input.args.env ?? null, |
| 196 | cwd: input.args.cwd ?? null, | 203 | cwd: input.args.cwd ?? null, |
| 197 | workspaceId: input.workspaceId, | 204 | scopeId: input.scopeId, |
| 198 | actorAccountId: input.accountId, | 205 | actorScopeId: input.actorScopeId, |
| 199 | executionId: input.executionId, | 206 | executionId: input.executionId, |
| 200 | interactionId: input.interactionId, | 207 | interactionId: input.interactionId, |
| 201 | } satisfies ExecutorMcpSourceInput; | 208 | } satisfies ExecutorMcpSourceInput; |
| @@ -205,8 +212,8 @@ const prepareExecutorAddSourceInput = (input: { · 3 unmodified lines | |||
| 205 | const args = input.args as ExecutorGoogleDiscoveryToolArgs; | 212 | const args = input.args as ExecutorGoogleDiscoveryToolArgs; |
| 206 | return { | 213 | return { |
| 207 | ...args, | 214 | ...args, |
| 208 | workspaceId: input.workspaceId, | 215 | scopeId: input.scopeId, |
| 209 | actorAccountId: input.accountId, | 216 | actorScopeId: input.actorScopeId, |
| 210 | executionId: input.executionId, | 217 | executionId: input.executionId, |
| 211 | interactionId: input.interactionId, | 218 | interactionId: input.interactionId, |
| 212 | } satisfies Extract<ExecutorCredentialManagedSourceInput, { service: string; version: string }>; | 219 | } satisfies Extract<ExecutorCredentialManagedSourceInput, { service: string; version: string }>; |
| @@ -216,8 +223,8 @@ const prepareExecutorAddSourceInput = (input: { · 3 unmodified lines | |||
| 216 | const args = input.args as ExecutorOpenApiToolArgs; | 223 | const args = input.args as ExecutorOpenApiToolArgs; |
| 217 | return { | 224 | return { |
| 218 | ...args, | 225 | ...args, |
| 219 | workspaceId: input.workspaceId, | 226 | scopeId: input.scopeId, |
| 220 | actorAccountId: input.accountId, | 227 | actorScopeId: input.actorScopeId, |
| 221 | executionId: input.executionId, | 228 | executionId: input.executionId, |
| 222 | interactionId: input.interactionId, | 229 | interactionId: input.interactionId, |
| 223 | } satisfies Extract<ExecutorCredentialManagedSourceInput, { specUrl: string }>; | 230 | } satisfies Extract<ExecutorCredentialManagedSourceInput, { specUrl: string }>; |
| @@ -226,8 +233,8 @@ const prepareExecutorAddSourceInput = (input: { · 2 unmodified lines | |||
| 226 | const args = input.args as ExecutorGraphqlToolArgs; | 233 | const args = input.args as ExecutorGraphqlToolArgs; |
| 227 | return { | 234 | return { |
| 228 | ...args, | 235 | ...args, |
| 229 | workspaceId: input.workspaceId, | 236 | scopeId: input.scopeId, |
| 230 | actorAccountId: input.accountId, | 237 | actorScopeId: input.actorScopeId, |
| 231 | executionId: input.executionId, | 238 | executionId: input.executionId, |
| 232 | interactionId: input.interactionId, | 239 | interactionId: input.interactionId, |
| 233 | } satisfies Extract<ExecutorCredentialManagedSourceInput, { kind: "graphql" }>; | 240 | } satisfies Extract<ExecutorCredentialManagedSourceInput, { kind: "graphql" }>; |
| @@ -235,13 +242,13 @@ const prepareExecutorAddSourceInput = (input: { · 1 unmodified line | |||
| 235 | 242 | ||
| 236 | const resolveLocalCredentialUrl = (input: { | 243 | const resolveLocalCredentialUrl = (input: { |
| 237 | baseUrl: string; | 244 | baseUrl: string; |
| 238 | workspaceId: WorkspaceId; | 245 | scopeId: ScopeId; |
| 239 | sourceId: Source["id"]; | 246 | sourceId: Source["id"]; |
| 240 | executionId: string; | 247 | executionId: string; |
| 241 | interactionId: string; | 248 | interactionId: string; |
| 242 | }): string => | 249 | }): string => |
| 243 | new URL( | 250 | new URL( |
| 244 | `/v1/workspaces/${encodeURIComponent(input.workspaceId)}/sources/${encodeURIComponent(input.sourceId)}/credentials?interactionId=${encodeURIComponent(`${input.executionId}:${input.interactionId}`)}`, | 251 | `/v1/workspaces/${encodeURIComponent(input.scopeId)}/sources/${encodeURIComponent(input.sourceId)}/credentials?interactionId=${encodeURIComponent(`${input.executionId}:${input.interactionId}`)}`, |
| 245 | input.baseUrl, | 252 | input.baseUrl, |
| 246 | ).toString(); | 253 | ).toString(); |
| 247 | 254 | ||
| @@ -282,7 +289,7 @@ const promptForSourceCredentialSelection = (input: { · 34 unmodified lines | |||
| 282 | : `Open the secure credential page to connect ${input.source.name}`, | 289 | : `Open the secure credential page to connect ${input.source.name}`, |
| 283 | url: resolveLocalCredentialUrl({ | 290 | url: resolveLocalCredentialUrl({ |
| 284 | baseUrl: input.localServerBaseUrl, | 291 | baseUrl: input.localServerBaseUrl, |
| 285 | workspaceId: input.args.workspaceId, | 292 | scopeId: input.args.scopeId, |
| 286 | sourceId: input.args.sourceId, | 293 | sourceId: input.args.sourceId, |
| 287 | executionId: input.executionId, | 294 | executionId: input.executionId, |
| 288 | interactionId: input.interactionId, | 295 | interactionId: input.interactionId, |
| @@ -312,14 +319,14 @@ const promptForSourceCredentialSelection = (input: { · 23 unmodified lines | |||
| 312 | }); | 319 | }); |
| 313 | 320 | ||
| 314 | export const createExecutorToolMap = (input: { | 321 | export const createExecutorToolMap = (input: { |
| 315 | workspaceId: WorkspaceId; | 322 | scopeId: ScopeId; |
| 316 | accountId: AccountId; | 323 | actorScopeId: ScopeId; |
| 317 | sourceAuthService: RuntimeSourceAuthService; | 324 | sourceAuthService: RuntimeSourceAuthService; |
| 318 | installationStore: InstallationStoreShape; | 325 | installationStore: InstallationStoreShape; |
| 319 | workspaceConfigStore: WorkspaceConfigStoreShape; | 326 | scopeConfigStore: ScopeConfigStoreShape; |
| 320 | workspaceStateStore: WorkspaceStateStoreShape; | 327 | scopeStateStore: ScopeStateStoreShape; |
| 321 | sourceArtifactStore: SourceArtifactStoreShape; | 328 | sourceArtifactStore: SourceArtifactStoreShape; |
| 322 | runtimeLocalWorkspace: RuntimeLocalWorkspaceState | null; | 329 | runtimeLocalScope: RuntimeLocalScopeState | null; |
| 323 | }): ToolMap => ({ | 330 | }): ToolMap => ({ |
| 324 | "executor.sources.add": toTool({ | 331 | "executor.sources.add": toTool({ |
| 325 | tool: { | 332 | tool: { |
| @@ -333,8 +340,8 @@ export const createExecutorToolMap = (input: { · 7 unmodified lines | |||
| 333 | ); | 340 | ); |
| 334 | const preparedArgs = prepareExecutorAddSourceInput({ | 341 | const preparedArgs = prepareExecutorAddSourceInput({ |
| 335 | args, | 342 | args, |
| 336 | workspaceId: input.workspaceId, | 343 | scopeId: input.scopeId, |
| 337 | accountId: input.accountId, | 344 | actorScopeId: input.actorScopeId, |
| 338 | executionId, | 345 | executionId, |
| 339 | interactionId, | 346 | interactionId, |
| 340 | }); | 347 | }); |
| @@ -356,11 +363,11 @@ export const createExecutorToolMap = (input: { · 15 unmodified lines | |||
| 356 | ), | 363 | ), |
| 357 | { | 364 | { |
| 358 | installationStore: input.installationStore, | 365 | installationStore: input.installationStore, |
| 359 | workspaceConfigStore: input.workspaceConfigStore, | 366 | scopeConfigStore: input.scopeConfigStore, |
| 360 | workspaceStateStore: input.workspaceStateStore, | 367 | scopeStateStore: input.scopeStateStore, |
| 361 | sourceArtifactStore: input.sourceArtifactStore, | 368 | sourceArtifactStore: input.sourceArtifactStore, |
| 362 | }, | 369 | }, |
| 363 | input.runtimeLocalWorkspace, | 370 | input.runtimeLocalScope, |
| 364 | ); | 371 | ); |
| 365 | 372 | ||
| 366 | if (result.kind === "connected") { | 373 | if (result.kind === "connected") { |
| @@ -379,7 +386,7 @@ export const createExecutorToolMap = (input: { · 12 unmodified lines | |||
| 379 | promptForSourceCredentialSelection({ | 386 | promptForSourceCredentialSelection({ |
| 380 | args: { | 387 | args: { |
| 381 | ...pendingArgs, | 388 | ...pendingArgs, |
| 382 | workspaceId: input.workspaceId, | 389 | scopeId: input.scopeId, |
| 383 | sourceId: pendingResult.source.id, | 390 | sourceId: pendingResult.source.id, |
| 384 | }, | 391 | }, |
| 385 | credentialSlot: pendingResult.credentialSlot, | 392 | credentialSlot: pendingResult.credentialSlot, |
| @@ -395,11 +402,11 @@ export const createExecutorToolMap = (input: { · 9 unmodified lines | |||
| 395 | }), | 402 | }), |
| 396 | { | 403 | { |
| 397 | installationStore: input.installationStore, | 404 | installationStore: input.installationStore, |
| 398 | workspaceConfigStore: input.workspaceConfigStore, | 405 | scopeConfigStore: input.scopeConfigStore, |
| 399 | workspaceStateStore: input.workspaceStateStore, | 406 | scopeStateStore: input.scopeStateStore, |
| 400 | sourceArtifactStore: input.sourceArtifactStore, | 407 | sourceArtifactStore: input.sourceArtifactStore, |
| 401 | }, | 408 | }, |
| 402 | input.runtimeLocalWorkspace, | 409 | input.runtimeLocalScope, |
| 403 | ); | 410 | ); |
| 404 | 411 | ||
| 405 | pendingArgs = pendingResult.credentialSlot === "import" | 412 | pendingArgs = pendingResult.credentialSlot === "import" |
| @@ -431,11 +438,11 @@ export const createExecutorToolMap = (input: { · 25 unmodified lines | |||
| 431 | ), | 438 | ), |
| 432 | { | 439 | { |
| 433 | installationStore: input.installationStore, | 440 | installationStore: input.installationStore, |
| 434 | workspaceConfigStore: input.workspaceConfigStore, | 441 | scopeConfigStore: input.scopeConfigStore, |
| 435 | workspaceStateStore: input.workspaceStateStore, | 442 | scopeStateStore: input.scopeStateStore, |
| 436 | sourceArtifactStore: input.sourceArtifactStore, | 443 | sourceArtifactStore: input.sourceArtifactStore, |
| 437 | }, | 444 | }, |
| 438 | input.runtimeLocalWorkspace, | 445 | input.runtimeLocalScope, |
| 439 | ); | 446 | ); |
| 440 | 447 | ||
| 441 | if (completed.kind === "connected") { | 448 | if (completed.kind === "connected") { |
| @@ -481,11 +488,11 @@ export const createExecutorToolMap = (input: { · 39 unmodified lines | |||
| 481 | }), | 488 | }), |
| 482 | { | 489 | { |
| 483 | installationStore: input.installationStore, | 490 | installationStore: input.installationStore, |
| 484 | workspaceConfigStore: input.workspaceConfigStore, | 491 | scopeConfigStore: input.scopeConfigStore, |
| 485 | workspaceStateStore: input.workspaceStateStore, | 492 | scopeStateStore: input.scopeStateStore, |
| 486 | sourceArtifactStore: input.sourceArtifactStore, | 493 | sourceArtifactStore: input.sourceArtifactStore, |
| 487 | }, | 494 | }, |
| 488 | input.runtimeLocalWorkspace, | 495 | input.runtimeLocalScope, |
| 489 | ); | 496 | ); |
| 490 | 497 | ||
| 491 | if (response.action !== "accept") { | 498 | if (response.action !== "accept") { |
| @@ -494,17 +501,17 @@ export const createExecutorToolMap = (input: { · 2 unmodified lines | |||
| 494 | 501 | ||
| 495 | const connected = await runEffect( | 502 | const connected = await runEffect( |
| 496 | input.sourceAuthService.getSourceById({ | 503 | input.sourceAuthService.getSourceById({ |
| 497 | workspaceId: input.workspaceId, | 504 | scopeId: input.scopeId, |
| 498 | sourceId: result.source.id, | 505 | sourceId: result.source.id, |
| 499 | actorAccountId: input.accountId, | 506 | actorScopeId: input.actorScopeId, |
| 500 | }), | 507 | }), |
| 501 | { | 508 | { |
| 502 | installationStore: input.installationStore, | 509 | installationStore: input.installationStore, |
| 503 | workspaceConfigStore: input.workspaceConfigStore, | 510 | scopeConfigStore: input.scopeConfigStore, |
| 504 | workspaceStateStore: input.workspaceStateStore, | 511 | scopeStateStore: input.scopeStateStore, |
| 505 | sourceArtifactStore: input.sourceArtifactStore, | 512 | sourceArtifactStore: input.sourceArtifactStore, |
| 506 | }, | 513 | }, |
| 507 | input.runtimeLocalWorkspace, | 514 | input.runtimeLocalScope, |
| 508 | ); | 515 | ); |
| 509 | return toSerializableValue(connected); | 516 | return toSerializableValue(connected); |
| 510 | }, | 517 | }, |
| @@ -1,8 +1,18 @@ | |||
| 1 | import { createServer, type IncomingMessage } from "node:http"; | 1 | import { |
| 2 | createServer, | ||
| 3 | type IncomingMessage, | ||
| 4 | } from "node:http"; | ||
| 2 | 5 | ||
| 3 | import { afterEach, describe, expect, it } from "@effect/vitest"; | 6 | import { |
| 7 | afterEach, | ||
| 8 | describe, | ||
| 9 | expect, | ||
| 10 | it, | ||
| 11 | } from "@effect/vitest"; | ||
| 4 | 12 | ||
| 5 | import { createGraphqlToolFromPersistedOperation } from "./graphql-tools"; | 13 | import { |
| 14 | createGraphqlToolFromPersistedOperation, | ||
| 15 | } from "./graphql-tools"; | ||
| 6 | 16 | ||
| 7 | type CapturedRequest = { | 17 | type CapturedRequest = { |
| 8 | path: string; | 18 | path: string; |
| @@ -1,5 +1,9 @@ | |||
| 1 | import { createServer } from "node:http"; | 1 | import { |
| 2 | import { fileURLToPath } from "node:url"; | 2 | createServer, |
| 3 | } from "node:http"; | ||
| 4 | import { | ||
| 5 | fileURLToPath, | ||
| 6 | } from "node:url"; | ||
| 3 | 7 | ||
| 4 | import { | 8 | import { |
| 5 | FileSystem, | 9 | FileSystem, |
| @@ -9,7 +13,9 @@ import { · 3 unmodified lines | |||
| 9 | HttpApiSchema, | 13 | HttpApiSchema, |
| 10 | OpenApi, | 14 | OpenApi, |
| 11 | } from "@effect/platform"; | 15 | } from "@effect/platform"; |
| 12 | import { NodeFileSystem } from "@effect/platform-node"; | 16 | import { |
| 17 | NodeFileSystem, | ||
| 18 | } from "@effect/platform-node"; | ||
| 13 | import { | 19 | import { |
| 14 | buildOpenApiToolPresentation, | 20 | buildOpenApiToolPresentation, |
| 15 | compileOpenApiToolDefinitions, | 21 | compileOpenApiToolDefinitions, |
| @@ -21,7 +27,11 @@ import { · 5 unmodified lines | |||
| 21 | compileGoogleDiscoveryToolDefinitions, | 27 | compileGoogleDiscoveryToolDefinitions, |
| 22 | extractGoogleDiscoveryManifest, | 28 | extractGoogleDiscoveryManifest, |
| 23 | } from "@executor/source-google-discovery"; | 29 | } from "@executor/source-google-discovery"; |
| 24 | import { describe, expect, it } from "@effect/vitest"; | 30 | import { |
| 31 | describe, | ||
| 32 | expect, | ||
| 33 | it, | ||
| 34 | } from "@effect/vitest"; | ||
| 25 | 35 | ||
| 26 | import type { | 36 | import type { |
| 27 | Source, | 37 | Source, |
| @@ -32,13 +42,19 @@ import { · 4 unmodified lines | |||
| 32 | SourceCatalogIdSchema, | 42 | SourceCatalogIdSchema, |
| 33 | SourceCatalogRevisionIdSchema, | 43 | SourceCatalogRevisionIdSchema, |
| 34 | SourceIdSchema, | 44 | SourceIdSchema, |
| 35 | WorkspaceIdSchema, | 45 | ScopeIdSchema, |
| 36 | } from "#schema"; | 46 | } from "#schema"; |
| 37 | import * as Effect from "effect/Effect"; | 47 | import * as Effect from "effect/Effect"; |
| 38 | import { Schema } from "effect"; | 48 | import { |
| 49 | Schema, | ||
| 50 | } from "effect"; | ||
| 39 | 51 | ||
| 40 | import { projectCatalogForAgentSdk } from "@executor/ir/catalog"; | 52 | import { |
| 41 | import type { CatalogSnapshotV1 } from "@executor/ir/model"; | 53 | projectCatalogForAgentSdk, |
| 54 | } from "@executor/ir/catalog"; | ||
| 55 | import type { | ||
| 56 | CatalogSnapshotV1, | ||
| 57 | } from "@executor/ir/model"; | ||
| 42 | import { | 58 | import { |
| 43 | createCatalogTypeProjector, | 59 | createCatalogTypeProjector, |
| 44 | projectedCatalogTypeRoots, | 60 | projectedCatalogTypeRoots, |
| @@ -52,12 +68,20 @@ import { · 7 unmodified lines | |||
| 52 | expandCatalogToolByPath, | 68 | expandCatalogToolByPath, |
| 53 | type LoadedSourceCatalog, | 69 | type LoadedSourceCatalog, |
| 54 | } from "../catalog/source/runtime"; | 70 | } from "../catalog/source/runtime"; |
| 55 | import { invokeIrTool } from "../execution/ir-execution"; | 71 | import { |
| 56 | import { createGoogleDiscoveryCatalogSnapshot } from "@executor/source-google-discovery"; | 72 | invokeIrTool, |
| 57 | import { createGraphqlCatalogSnapshot } from "@executor/source-graphql"; | 73 | } from "../execution/ir-execution"; |
| 58 | import { createOpenApiCatalogSnapshot } from "@executor/source-openapi"; | 74 | import { |
| 75 | createGoogleDiscoveryCatalogSnapshot, | ||
| 76 | } from "@executor/source-google-discovery"; | ||
| 77 | import { | ||
| 78 | createGraphqlCatalogSnapshot, | ||
| 79 | } from "@executor/source-graphql"; | ||
| 80 | import { | ||
| 81 | createOpenApiCatalogSnapshot, | ||
| 82 | } from "@executor/source-openapi"; | ||
| 59 | 83 | ||
| 60 | const FIXTURE_WORKSPACE_ID = WorkspaceIdSchema.make("ws_source_fixture_matrix"); | 84 | const FIXTURE_WORKSPACE_ID = ScopeIdSchema.make("ws_source_fixture_matrix"); |
| 61 | 85 | ||
| 62 | const readFixture = (name: string) => | 86 | const readFixture = (name: string) => |
| 63 | FileSystem.FileSystem.pipe( | 87 | FileSystem.FileSystem.pipe( |
| @@ -79,7 +103,7 @@ const makeSource = (input: { · 15 unmodified lines | |||
| 79 | binding: Source["binding"]; | 103 | binding: Source["binding"]; |
| 80 | }): Source => ({ | 104 | }): Source => ({ |
| 81 | id: SourceIdSchema.make(input.id), | 105 | id: SourceIdSchema.make(input.id), |
| 82 | workspaceId: FIXTURE_WORKSPACE_ID, | 106 | scopeId: FIXTURE_WORKSPACE_ID, |
| 83 | name: input.name, | 107 | name: input.name, |
| 84 | kind: input.kind, | 108 | kind: input.kind, |
| 85 | endpoint: input.endpoint, | 109 | endpoint: input.endpoint, |
| @@ -107,7 +131,7 @@ const makeLoadedCatalog = (input: { · 21 unmodified lines | |||
| 107 | ); | 131 | ); |
| 108 | const sourceRecord = { | 132 | const sourceRecord = { |
| 109 | id: input.source.id, | 133 | id: input.source.id, |
| 110 | workspaceId: input.source.workspaceId, | 134 | scopeId: input.source.scopeId, |
| 111 | catalogId, | 135 | catalogId, |
| 112 | catalogRevisionId: revisionId, | 136 | catalogRevisionId: revisionId, |
| 113 | name: input.source.name, | 137 | name: input.source.name, |
| @@ -725,8 +749,8 @@ describe("source adapter fixture matrix", () => { · 611 unmodified lines | |||
| 725 | 749 | ||
| 726 | const getItemResult = await Effect.runPromise( | 750 | const getItemResult = await Effect.runPromise( |
| 727 | invokeIrTool({ | 751 | invokeIrTool({ |
| 728 | workspaceId: source.workspaceId, | 752 | scopeId: source.scopeId, |
| 729 | accountId: "acct_fixture" as any, | 753 | actorScopeId: "acct_fixture" as any, |
| 730 | tool: getItemTool, | 754 | tool: getItemTool, |
| 731 | auth, | 755 | auth, |
| 732 | args: { | 756 | args: { |
| @@ -741,8 +765,8 @@ describe("source adapter fixture matrix", () => { · 8 unmodified lines | |||
| 741 | ); | 765 | ); |
| 742 | const submitFormResult = await Effect.runPromise( | 766 | const submitFormResult = await Effect.runPromise( |
| 743 | invokeIrTool({ | 767 | invokeIrTool({ |
| 744 | workspaceId: source.workspaceId, | 768 | scopeId: source.scopeId, |
| 745 | accountId: "acct_fixture" as any, | 769 | actorScopeId: "acct_fixture" as any, |
| 746 | tool: submitFormTool, | 770 | tool: submitFormTool, |
| 747 | auth, | 771 | auth, |
| 748 | args: { | 772 | args: { |
| @@ -898,8 +922,8 @@ describe("source adapter fixture matrix", () => { · 149 unmodified lines | |||
| 898 | 922 | ||
| 899 | const result = await Effect.runPromise( | 923 | const result = await Effect.runPromise( |
| 900 | invokeIrTool({ | 924 | invokeIrTool({ |
| 901 | workspaceId: source.workspaceId, | 925 | scopeId: source.scopeId, |
| 902 | accountId: "acct_fixture" as any, | 926 | actorScopeId: "acct_fixture" as any, |
| 903 | tool, | 927 | tool, |
| 904 | auth, | 928 | auth, |
| 905 | args: { | 929 | args: { |
| @@ -1332,8 +1356,8 @@ describe("source adapter fixture matrix", () => { · 426 unmodified lines | |||
| 1332 | } as const; | 1356 | } as const; |
| 1333 | 1357 | ||
| 1334 | const result = yield* invokeIrTool({ | 1358 | const result = yield* invokeIrTool({ |
| 1335 | workspaceId: source.workspaceId, | 1359 | scopeId: source.scopeId, |
| 1336 | accountId: "acct_fixture" as any, | 1360 | actorScopeId: "acct_fixture" as any, |
| 1337 | tool, | 1361 | tool, |
| 1338 | auth, | 1362 | auth, |
| 1339 | args: {}, | 1363 | args: {}, |
| @@ -1,14 +1,30 @@ | |||
| 1 | import { createServer } from "node:http"; | 1 | import { |
| 2 | createServer, | ||
| 3 | } from "node:http"; | ||
| 2 | 4 | ||
| 3 | import { describe, expect, it } from "@effect/vitest"; | 5 | import { |
| 4 | import { SourceIdSchema } from "#schema"; | 6 | describe, |
| 7 | expect, | ||
| 8 | it, | ||
| 9 | } from "@effect/vitest"; | ||
| 10 | import { | ||
| 11 | SourceIdSchema, | ||
| 12 | } from "#schema"; | ||
| 5 | 13 | ||
| 6 | import * as Effect from "effect/Effect"; | 14 | import * as Effect from "effect/Effect"; |
| 7 | 15 | ||
| 8 | import { googleDiscoverySourceAdapter } from "./google-discovery"; | 16 | import { |
| 9 | import { snapshotFromSourceCatalogSyncResult } from "../catalog-sync-result"; | 17 | googleDiscoverySourceAdapter, |
| 10 | import { createSourceFromPayload } from "../source-definitions"; | 18 | } from "./google-discovery"; |
| 11 | import { runtimeEffectError } from "../../effect-errors"; | 19 | import { |
| 20 | snapshotFromSourceCatalogSyncResult, | ||
| 21 | } from "../catalog-sync-result"; | ||
| 22 | import { | ||
| 23 | createSourceFromPayload, | ||
| 24 | } from "../source-definitions"; | ||
| 25 | import { | ||
| 26 | runtimeEffectError, | ||
| 27 | } from "../../effect-errors"; | ||
| 12 | 28 | ||
| 13 | const fetchLiveDiscoveryDocument = async (): Promise<string> => { | 29 | const fetchLiveDiscoveryDocument = async (): Promise<string> => { |
| 14 | const response = await fetch("https://www.googleapis.com/discovery/v1/apis/sheets/v4/rest", { | 30 | const response = await fetch("https://www.googleapis.com/discovery/v1/apis/sheets/v4/rest", { |
| @@ -66,7 +82,7 @@ describe("google discovery source adapter", () => { · 51 unmodified lines | |||
| 66 | await withStaticServer(discoveryDocument, async (discoveryUrl) => { | 82 | await withStaticServer(discoveryDocument, async (discoveryUrl) => { |
| 67 | const source = await Effect.runPromise( | 83 | const source = await Effect.runPromise( |
| 68 | createSourceFromPayload({ | 84 | createSourceFromPayload({ |
| 69 | workspaceId: "ws_test" as any, | 85 | scopeId: "ws_test" as any, |
| 70 | sourceId: SourceIdSchema.make(`src_${crypto.randomUUID()}`), | 86 | sourceId: SourceIdSchema.make(`src_${crypto.randomUUID()}`), |
| 71 | payload: { | 87 | payload: { |
| 72 | name: "Google Sheets", | 88 | name: "Google Sheets", |
| @@ -1,13 +1,29 @@ | |||
| 1 | import { createServer } from "node:http"; | 1 | import { |
| 2 | createServer, | ||
| 3 | } from "node:http"; | ||
| 2 | 4 | ||
| 3 | import { describe, expect, it } from "@effect/vitest"; | 5 | import { |
| 4 | import { SourceIdSchema } from "#schema"; | 6 | describe, |
| 7 | expect, | ||
| 8 | it, | ||
| 9 | } from "@effect/vitest"; | ||
| 10 | import { | ||
| 11 | SourceIdSchema, | ||
| 12 | } from "#schema"; | ||
| 5 | import * as Effect from "effect/Effect"; | 13 | import * as Effect from "effect/Effect"; |
| 6 | import { vi } from "vitest"; | 14 | import { |
| 15 | vi, | ||
| 16 | } from "vitest"; | ||
| 7 | 17 | ||
| 8 | import { createSourceFromPayload } from "../source-definitions"; | 18 | import { |
| 9 | import { graphqlSourceAdapter } from "./graphql"; | 19 | createSourceFromPayload, |
| 10 | import { runtimeEffectError } from "../../effect-errors"; | 20 | } from "../source-definitions"; |
| 21 | import { | ||
| 22 | graphqlSourceAdapter, | ||
| 23 | } from "./graphql"; | ||
| 24 | import { | ||
| 25 | runtimeEffectError, | ||
| 26 | } from "../../effect-errors"; | ||
| 11 | 27 | ||
| 12 | const toError = (cause: unknown): Error => | 28 | const toError = (cause: unknown): Error => |
| 13 | cause instanceof Error ? cause : new Error(String(cause)); | 29 | cause instanceof Error ? cause : new Error(String(cause)); |
| @@ -92,7 +108,7 @@ describe("graphql source adapter", () => { · 78 unmodified lines | |||
| 92 | ); | 108 | ); |
| 93 | 109 | ||
| 94 | const source = yield* createSourceFromPayload({ | 110 | const source = yield* createSourceFromPayload({ |
| 95 | workspaceId: "ws_test" as any, | 111 | scopeId: "ws_test" as any, |
| 96 | sourceId: SourceIdSchema.make(`src_${crypto.randomUUID()}`), | 112 | sourceId: SourceIdSchema.make(`src_${crypto.randomUUID()}`), |
| 97 | payload: { | 113 | payload: { |
| 98 | name: "GraphQL Timeout", | 114 | name: "GraphQL Timeout", |
| @@ -4,9 +4,13 @@ import { · 3 unmodified lines | |||
| 4 | createSourceAdapterComposition, | 4 | createSourceAdapterComposition, |
| 5 | type SourceAdapter, | 5 | type SourceAdapter, |
| 6 | } from "@executor/source-core"; | 6 | } from "@executor/source-core"; |
| 7 | import { externalSourceAdapters } from "@executor/source-builtins"; | 7 | import { |
| 8 | externalSourceAdapters, | ||
| 9 | } from "@executor/source-builtins"; | ||
| 8 | 10 | ||
| 9 | import { internalSourceAdapter } from "./internal"; | 11 | import { |
| 12 | internalSourceAdapter, | ||
| 13 | } from "./internal"; | ||
| 10 | 14 | ||
| 11 | export type * from "@executor/source-core"; | 15 | export type * from "@executor/source-core"; |
| 12 | 16 | ||
| @@ -10,7 +10,9 @@ import { · 9 unmodified lines | |||
| 10 | type Source, | 10 | type Source, |
| 11 | type SourceAdapter, | 11 | type SourceAdapter, |
| 12 | } from "@executor/source-core"; | 12 | } from "@executor/source-core"; |
| 13 | import { runtimeEffectError } from "../../effect-errors"; | 13 | import { |
| 14 | runtimeEffectError, | ||
| 15 | } from "../../effect-errors"; | ||
| 14 | 16 | ||
| 15 | const InternalBindingConfigSchema = Schema.Struct({}); | 17 | const InternalBindingConfigSchema = Schema.Struct({}); |
| 16 | 18 | ||
| @@ -1,10 +1,24 @@ | |||
| 1 | import { randomUUID } from "node:crypto"; | 1 | import { |
| 2 | randomUUID, | ||
| 3 | } from "node:crypto"; | ||
| 2 | 4 | ||
| 3 | import { createMcpExpressApp } from "@modelcontextprotocol/sdk/server/express.js"; | 5 | import { |
| 4 | import type { OAuthClientProvider } from "@modelcontextprotocol/sdk/client/auth.js"; | 6 | createMcpExpressApp, |
| 5 | import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; | 7 | } from "@modelcontextprotocol/sdk/server/express.js"; |
| 6 | import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js"; | 8 | import type { |
| 7 | import { describe, expect, it } from "@effect/vitest"; | 9 | OAuthClientProvider, |
| 10 | } from "@modelcontextprotocol/sdk/client/auth.js"; | ||
| 11 | import { | ||
| 12 | McpServer, | ||
| 13 | } from "@modelcontextprotocol/sdk/server/mcp.js"; | ||
| 14 | import { | ||
| 15 | StreamableHTTPServerTransport, | ||
| 16 | } from "@modelcontextprotocol/sdk/server/streamableHttp.js"; | ||
| 17 | import { | ||
| 18 | describe, | ||
| 19 | expect, | ||
| 20 | it, | ||
| 21 | } from "@effect/vitest"; | ||
| 8 | import { | 22 | import { |
| 9 | SourceCatalogIdSchema, | 23 | SourceCatalogIdSchema, |
| 10 | SourceCatalogRevisionIdSchema, | 24 | SourceCatalogRevisionIdSchema, |
| @@ -17,20 +31,39 @@ import type { · 6 unmodified lines | |||
| 17 | } from "#schema"; | 31 | } from "#schema"; |
| 18 | 32 | ||
| 19 | import * as Effect from "effect/Effect"; | 33 | import * as Effect from "effect/Effect"; |
| 20 | import { z } from "zod/v4"; | 34 | import { |
| 35 | z, | ||
| 36 | } from "zod/v4"; | ||
| 21 | 37 | ||
| 22 | import { projectCatalogForAgentSdk } from "@executor/ir/catalog"; | 38 | import { |
| 23 | import type { CatalogSnapshotV1 } from "@executor/ir/model"; | 39 | projectCatalogForAgentSdk, |
| 24 | import { createCatalogTypeProjector, projectedCatalogTypeRoots } from "../../catalog/catalog-typescript"; | 40 | } from "@executor/ir/catalog"; |
| 25 | import { invokeIrTool } from "../../execution/ir-execution"; | 41 | import type { |
| 42 | CatalogSnapshotV1, | ||
| 43 | } from "@executor/ir/model"; | ||
| 44 | import { | ||
| 45 | createCatalogTypeProjector, | ||
| 46 | projectedCatalogTypeRoots, | ||
| 47 | } from "../../catalog/catalog-typescript"; | ||
| 48 | import { | ||
| 49 | invokeIrTool, | ||
| 50 | } from "../../execution/ir-execution"; | ||
| 26 | import { | 51 | import { |
| 27 | expandCatalogToolByPath, | 52 | expandCatalogToolByPath, |
| 28 | type LoadedSourceCatalog, | 53 | type LoadedSourceCatalog, |
| 29 | } from "../../catalog/source/runtime"; | 54 | } from "../../catalog/source/runtime"; |
| 30 | import { snapshotFromSourceCatalogSyncResult } from "../catalog-sync-result"; | 55 | import { |
| 31 | import { createSourceFromPayload } from "../source-definitions"; | 56 | snapshotFromSourceCatalogSyncResult, |
| 32 | import { mcpSourceAdapter } from "./mcp"; | 57 | } from "../catalog-sync-result"; |
| 33 | import { runtimeEffectError } from "../../effect-errors"; | 58 | import { |
| 59 | createSourceFromPayload, | ||
| 60 | } from "../source-definitions"; | ||
| 61 | import { | ||
| 62 | mcpSourceAdapter, | ||
| 63 | } from "./mcp"; | ||
| 64 | import { | ||
| 65 | runtimeEffectError, | ||
| 66 | } from "../../effect-errors"; | ||
| 34 | 67 | ||
| 35 | type RealMcpServer = { | 68 | type RealMcpServer = { |
| 36 | endpoint: string; | 69 | endpoint: string; |
| @@ -47,7 +80,7 @@ const makeLoadedCatalog = (input: { · 10 unmodified lines | |||
| 47 | ); | 80 | ); |
| 48 | const sourceRecord = { | 81 | const sourceRecord = { |
| 49 | id: input.source.id, | 82 | id: input.source.id, |
| 50 | workspaceId: input.source.workspaceId, | 83 | scopeId: input.source.scopeId, |
| 51 | catalogId, | 84 | catalogId, |
| 52 | catalogRevisionId: revisionId, | 85 | catalogRevisionId: revisionId, |
| 53 | name: input.source.name, | 86 | name: input.source.name, |
| @@ -535,9 +568,15 @@ const makeStatefulMcpServer = Effect.acquireRelease( · 481 unmodified lines | |||
| 535 | ); | 568 | ); |
| 536 | 569 | ||
| 537 | const STDIO_TEST_SERVER_SCRIPT = ` | 570 | const STDIO_TEST_SERVER_SCRIPT = ` |
| 538 | import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; | 571 | import { |
| 539 | import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; | 572 | McpServer, |
| 540 | import { z } from "zod/v4"; | 573 | } from "@modelcontextprotocol/sdk/server/mcp.js"; |
| 574 | import { | ||
| 575 | StdioServerTransport, | ||
| 576 | } from "@modelcontextprotocol/sdk/server/stdio.js"; | ||
| 577 | import { | ||
| 578 | z, | ||
| 579 | } from "zod/v4"; | ||
| 541 | 580 | ||
| 542 | const server = new McpServer( | 581 | const server = new McpServer( |
| 543 | { name: "mcp-stdio-test-server", version: "1.0.0" }, | 582 | { name: "mcp-stdio-test-server", version: "1.0.0" }, |
| @@ -594,7 +633,7 @@ describe("mcp source adapter", () => { · 50 unmodified lines | |||
| 594 | Effect.gen(function* () { | 633 | Effect.gen(function* () { |
| 595 | const realServer = yield* makeRealMcpServer; | 634 | const realServer = yield* makeRealMcpServer; |
| 596 | const source = yield* createSourceFromPayload({ | 635 | const source = yield* createSourceFromPayload({ |
| 597 | workspaceId: "ws_test" as any, | 636 | scopeId: "ws_test" as any, |
| 598 | sourceId: SourceIdSchema.make(`src_${randomUUID()}`), | 637 | sourceId: SourceIdSchema.make(`src_${randomUUID()}`), |
| 599 | payload: { | 638 | payload: { |
| 600 | name: "MCP Demo", | 639 | name: "MCP Demo", |
| @@ -682,7 +721,7 @@ describe("mcp source adapter", () => { · 81 unmodified lines | |||
| 682 | Effect.gen(function* () { | 721 | Effect.gen(function* () { |
| 683 | const realServer = yield* makeRealMcpServer; | 722 | const realServer = yield* makeRealMcpServer; |
| 684 | const source = yield* createSourceFromPayload({ | 723 | const source = yield* createSourceFromPayload({ |
| 685 | workspaceId: "ws_test" as any, | 724 | scopeId: "ws_test" as any, |
| 686 | sourceId: SourceIdSchema.make(`src_${randomUUID()}`), | 725 | sourceId: SourceIdSchema.make(`src_${randomUUID()}`), |
| 687 | payload: { | 726 | payload: { |
| 688 | name: "MCP Demo", | 727 | name: "MCP Demo", |
| @@ -733,8 +772,8 @@ describe("mcp source adapter", () => { · 44 unmodified lines | |||
| 733 | } | 772 | } |
| 734 | 773 | ||
| 735 | const result = yield* invokeIrTool({ | 774 | const result = yield* invokeIrTool({ |
| 736 | workspaceId: source.workspaceId, | 775 | scopeId: source.scopeId, |
| 737 | accountId: "acct_test" as any, | 776 | actorScopeId: "acct_test" as any, |
| 738 | tool, | 777 | tool, |
| 739 | auth: { | 778 | auth: { |
| 740 | placements: [], | 779 | placements: [], |
| @@ -769,7 +808,7 @@ describe("mcp source adapter", () => { · 28 unmodified lines | |||
| 769 | const realServer = yield* makeAuthenticatedMcpServer("Bearer mcp-auth-token"); | 808 | const realServer = yield* makeAuthenticatedMcpServer("Bearer mcp-auth-token"); |
| 770 | const authProvider = makeStaticAuthProvider("mcp-auth-token"); | 809 | const authProvider = makeStaticAuthProvider("mcp-auth-token"); |
| 771 | const source = yield* createSourceFromPayload({ | 810 | const source = yield* createSourceFromPayload({ |
| 772 | workspaceId: "ws_test" as any, | 811 | scopeId: "ws_test" as any, |
| 773 | sourceId: SourceIdSchema.make(`src_${randomUUID()}`), | 812 | sourceId: SourceIdSchema.make(`src_${randomUUID()}`), |
| 774 | payload: { | 813 | payload: { |
| 775 | name: "Authenticated MCP Demo", | 814 | name: "Authenticated MCP Demo", |
| @@ -822,8 +861,8 @@ describe("mcp source adapter", () => { · 46 unmodified lines | |||
| 822 | } | 861 | } |
| 823 | 862 | ||
| 824 | const result = yield* invokeIrTool({ | 863 | const result = yield* invokeIrTool({ |
| 825 | workspaceId: source.workspaceId, | 864 | scopeId: source.scopeId, |
| 826 | accountId: "acct_test" as any, | 865 | actorScopeId: "acct_test" as any, |
| 827 | tool, | 866 | tool, |
| 828 | auth: resolvedAuth, | 867 | auth: resolvedAuth, |
| 829 | args: { | 868 | args: { |
| @@ -849,7 +888,7 @@ describe("mcp source adapter", () => { · 19 unmodified lines | |||
| 849 | Effect.gen(function* () { | 888 | Effect.gen(function* () { |
| 850 | const realServer = yield* makeStatefulMcpServer; | 889 | const realServer = yield* makeStatefulMcpServer; |
| 851 | const source = yield* createSourceFromPayload({ | 890 | const source = yield* createSourceFromPayload({ |
| 852 | workspaceId: "ws_test" as any, | 891 | scopeId: "ws_test" as any, |
| 853 | sourceId: SourceIdSchema.make(`src_${randomUUID()}`), | 892 | sourceId: SourceIdSchema.make(`src_${randomUUID()}`), |
| 854 | payload: { | 893 | payload: { |
| 855 | name: "Stateful MCP Demo", | 894 | name: "Stateful MCP Demo", |
| @@ -905,8 +944,8 @@ describe("mcp source adapter", () => { · 49 unmodified lines | |||
| 905 | } | 944 | } |
| 906 | 945 | ||
| 907 | const incrementResult = yield* invokeIrTool({ | 946 | const incrementResult = yield* invokeIrTool({ |
| 908 | workspaceId: source.workspaceId, | 947 | scopeId: source.scopeId, |
| 909 | accountId: "acct_test" as any, | 948 | actorScopeId: "acct_test" as any, |
| 910 | tool: incrementTool, | 949 | tool: incrementTool, |
| 911 | auth: { | 950 | auth: { |
| 912 | placements: [], | 951 | placements: [], |
| @@ -924,8 +963,8 @@ describe("mcp source adapter", () => { · 11 unmodified lines | |||
| 924 | }); | 963 | }); |
| 925 | 964 | ||
| 926 | const readResult = yield* invokeIrTool({ | 965 | const readResult = yield* invokeIrTool({ |
| 927 | workspaceId: source.workspaceId, | 966 | scopeId: source.scopeId, |
| 928 | accountId: "acct_test" as any, | 967 | actorScopeId: "acct_test" as any, |
| 929 | tool: readTool, | 968 | tool: readTool, |
| 930 | auth: { | 969 | auth: { |
| 931 | placements: [], | 970 | placements: [], |
| @@ -970,7 +1009,7 @@ describe("mcp source adapter", () => { · 38 unmodified lines | |||
| 970 | it.scoped("supports stdio MCP sources", () => | 1009 | it.scoped("supports stdio MCP sources", () => |
| 971 | Effect.gen(function* () { | 1010 | Effect.gen(function* () { |
| 972 | const source = yield* createSourceFromPayload({ | 1011 | const source = yield* createSourceFromPayload({ |
| 973 | workspaceId: "ws_test" as any, | 1012 | scopeId: "ws_test" as any, |
| 974 | sourceId: SourceIdSchema.make(`src_${randomUUID()}`), | 1013 | sourceId: SourceIdSchema.make(`src_${randomUUID()}`), |
| 975 | payload: { | 1014 | payload: { |
| 976 | name: "Stdio MCP Demo", | 1015 | name: "Stdio MCP Demo", |
| @@ -1025,8 +1064,8 @@ describe("mcp source adapter", () => { · 48 unmodified lines | |||
| 1025 | } | 1064 | } |
| 1026 | 1065 | ||
| 1027 | const result = yield* invokeIrTool({ | 1066 | const result = yield* invokeIrTool({ |
| 1028 | workspaceId: source.workspaceId, | 1067 | scopeId: source.scopeId, |
| 1029 | accountId: "acct_test" as any, | 1068 | actorScopeId: "acct_test" as any, |
| 1030 | tool, | 1069 | tool, |
| 1031 | auth: { | 1070 | auth: { |
| 1032 | placements: [], | 1071 | placements: [], |
| @@ -9,7 +9,6 @@ import { · 8 unmodified lines | |||
| 9 | type SourceAdapterOauth2SetupConfig, | 9 | type SourceAdapterOauth2SetupConfig, |
| 10 | } from "@executor/source-core"; | 10 | } from "@executor/source-core"; |
| 11 | import { | 11 | import { |
| 12 | AccountId, | ||
| 13 | type CredentialSlot, | 12 | type CredentialSlot, |
| 14 | McpSourceAuthSessionDataJsonSchema, | 13 | McpSourceAuthSessionDataJsonSchema, |
| 15 | type McpSourceAuthSessionData, | 14 | type McpSourceAuthSessionData, |
| @@ -30,12 +29,12 @@ import { · 14 unmodified lines | |||
| 30 | SourceSchema, | 29 | SourceSchema, |
| 31 | type SecretRef, | 30 | type SecretRef, |
| 32 | type StringMap, | 31 | type StringMap, |
| 33 | WorkspaceOauthClientIdSchema, | 32 | ScopeOauthClientIdSchema, |
| 34 | WorkspaceSourceOauthClientIdSchema, | 33 | ScopedSourceOauthClientIdSchema, |
| 35 | WorkspaceSourceOauthClientMetadataJsonSchema, | 34 | ScopedSourceOauthClientMetadataJsonSchema, |
| 36 | type WorkspaceOauthClient, | 35 | type ScopeOauthClient, |
| 37 | type WorkspaceSourceOauthClientRedirectMode, | 36 | type ScopedSourceOauthClientRedirectMode, |
| 38 | type WorkspaceId, | 37 | type ScopeId, |
| 39 | } from "#schema"; | 38 | } from "#schema"; |
| 40 | import * as Context from "effect/Context"; | 39 | import * as Context from "effect/Context"; |
| 41 | import * as Either from "effect/Either"; | 40 | import * as Either from "effect/Either"; |
| @@ -51,15 +50,17 @@ import { · 9 unmodified lines | |||
| 51 | type LiveExecutionManager, | 50 | type LiveExecutionManager, |
| 52 | } from "../execution/live"; | 51 | } from "../execution/live"; |
| 53 | import { | 52 | import { |
| 54 | getRuntimeLocalWorkspaceOption, | 53 | getRuntimeLocalScopeOption, |
| 55 | provideOptionalRuntimeLocalWorkspace, | 54 | provideOptionalRuntimeLocalScope, |
| 56 | type RuntimeLocalWorkspaceState, | 55 | type RuntimeLocalScopeState, |
| 57 | } from "../workspace/runtime-context"; | 56 | } from "../scope/runtime-context"; |
| 58 | import { | 57 | import { |
| 59 | exchangeMcpOAuthAuthorizationCode, | 58 | exchangeMcpOAuthAuthorizationCode, |
| 60 | startMcpOAuthAuthorization, | 59 | startMcpOAuthAuthorization, |
| 61 | } from "../auth/mcp-oauth"; | 60 | } from "../auth/mcp-oauth"; |
| 62 | import { createPersistedMcpOAuthSourceAuth } from "../auth/mcp-auth-provider"; | 61 | import { |
| 62 | createPersistedMcpOAuthSourceAuth, | ||
| 63 | } from "../auth/mcp-auth-provider"; | ||
| 63 | import { | 64 | import { |
| 64 | createSourceFromPayload, | 65 | createSourceFromPayload, |
| 65 | updateSourceFromPayload, | 66 | updateSourceFromPayload, |
| @@ -79,7 +80,7 @@ import { · 13 unmodified lines | |||
| 79 | SecretMaterialResolverService, | 80 | SecretMaterialResolverService, |
| 80 | SecretMaterialStorerService, | 81 | SecretMaterialStorerService, |
| 81 | type StoreSecretMaterial, | 82 | type StoreSecretMaterial, |
| 82 | } from "../workspace/secret-material-providers"; | 83 | } from "../scope/secret-material-providers"; |
| 83 | import { | 84 | import { |
| 84 | removeAuthLeaseAndSecrets, | 85 | removeAuthLeaseAndSecrets, |
| 85 | upsertOauth2AuthorizedUserLeaseFromTokenResponse, | 86 | upsertOauth2AuthorizedUserLeaseFromTokenResponse, |
| @@ -97,14 +98,23 @@ import { · 11 unmodified lines | |||
| 97 | createPkceCodeVerifier, | 98 | createPkceCodeVerifier, |
| 98 | exchangeOAuth2AuthorizationCode, | 99 | exchangeOAuth2AuthorizationCode, |
| 99 | } from "../auth/oauth2-pkce"; | 100 | } from "../auth/oauth2-pkce"; |
| 100 | import { startOauthLoopbackRedirectServer } from "../auth/oauth-loopback"; | 101 | import { |
| 102 | startOauthLoopbackRedirectServer, | ||
| 103 | } from "../auth/oauth-loopback"; | ||
| 101 | import { | 104 | import { |
| 102 | type RuntimeSourceStore, | 105 | type RuntimeSourceStore, |
| 103 | RuntimeSourceStoreService, | 106 | RuntimeSourceStoreService, |
| 104 | } from "./source-store"; | 107 | } from "./source-store"; |
| 105 | import type { WorkspaceStorageServices } from "../workspace/storage"; | 108 | import type { |
| 106 | import { ExecutorStateStore, type ExecutorStateStoreShape } from "../executor-state-store"; | 109 | ScopeStorageServices, |
| 107 | import { runtimeEffectError } from "../effect-errors"; | 110 | } from "../scope/storage"; |
| 111 | import { | ||
| 112 | ExecutorStateStore, | ||
| 113 | type ExecutorStateStoreShape, | ||
| 114 | } from "../executor-state-store"; | ||
| 115 | import { | ||
| 116 | runtimeEffectError, | ||
| 117 | } from "../effect-errors"; | ||
| 108 | 118 | ||
| 109 | const trimOrNull = (value: string | null | undefined): string | null => { | 119 | const trimOrNull = (value: string | null | undefined): string | null => { |
| 110 | if (value === null || value === undefined) { | 120 | if (value === null || value === undefined) { |
| @@ -199,11 +209,11 @@ const normalizeMcpEndpoint = (input: { · 88 unmodified lines | |||
| 199 | 209 | ||
| 200 | const resolveSourceCredentialOauthCompleteUrl = (input: { | 210 | const resolveSourceCredentialOauthCompleteUrl = (input: { |
| 201 | baseUrl: string; | 211 | baseUrl: string; |
| 202 | workspaceId: WorkspaceId; | 212 | scopeId: ScopeId; |
| 203 | sourceId: Source["id"]; | 213 | sourceId: Source["id"]; |
| 204 | }): string => | 214 | }): string => |
| 205 | new URL( | 215 | new URL( |
| 206 | `/v1/workspaces/${encodeURIComponent(input.workspaceId)}/sources/${encodeURIComponent(input.sourceId)}/credentials/oauth/complete`, | 216 | `/v1/workspaces/${encodeURIComponent(input.scopeId)}/sources/${encodeURIComponent(input.sourceId)}/credentials/oauth/complete`, |
| 207 | input.baseUrl, | 217 | input.baseUrl, |
| 208 | ).toString(); | 218 | ).toString(); |
| 209 | 219 | ||
| @@ -217,10 +227,10 @@ const resolveSourceOAuthCallbackUrl = (input: { · 7 unmodified lines | |||
| 217 | 227 | ||
| 218 | const resolveWorkspaceProviderOauthCompleteUrl = (input: { | 228 | const resolveWorkspaceProviderOauthCompleteUrl = (input: { |
| 219 | baseUrl: string; | 229 | baseUrl: string; |
| 220 | workspaceId: WorkspaceId; | 230 | scopeId: ScopeId; |
| 221 | }): string => | 231 | }): string => |
| 222 | new URL( | 232 | new URL( |
| 223 | `/v1/workspaces/${encodeURIComponent(input.workspaceId)}/oauth/provider/callback`, | 233 | `/v1/workspaces/${encodeURIComponent(input.scopeId)}/oauth/provider/callback`, |
| 224 | input.baseUrl, | 234 | input.baseUrl, |
| 225 | ).toString(); | 235 | ).toString(); |
| 226 | 236 | ||
| @@ -491,7 +501,7 @@ const serializeJson = (value: unknown): string | null => { · 264 unmodified lines | |||
| 491 | }; | 501 | }; |
| 492 | 502 | ||
| 493 | const updateSourceStatus = Effect.fn("source.status.update")((sourceStore: RuntimeSourceStore, source: Source, input: { | 503 | const updateSourceStatus = Effect.fn("source.status.update")((sourceStore: RuntimeSourceStore, source: Source, input: { |
| 494 | actorAccountId?: AccountId | null; | 504 | actorScopeId?: ScopeId | null; |
| 495 | status: Source["status"]; | 505 | status: Source["status"]; |
| 496 | lastError?: string | null; | 506 | lastError?: string | null; |
| 497 | auth?: Source["auth"]; | 507 | auth?: Source["auth"]; |
| @@ -499,9 +509,9 @@ const updateSourceStatus = Effect.fn("source.status.update")((sourceStore: Runti · 1 unmodified line | |||
| 499 | }) => | 509 | }) => |
| 500 | Effect.gen(function* () { | 510 | Effect.gen(function* () { |
| 501 | const latest = yield* sourceStore.loadSourceById({ | 511 | const latest = yield* sourceStore.loadSourceById({ |
| 502 | workspaceId: source.workspaceId, | 512 | scopeId: source.scopeId, |
| 503 | sourceId: source.id, | 513 | sourceId: source.id, |
| 504 | actorAccountId: input.actorAccountId, | 514 | actorScopeId: input.actorScopeId, |
| 505 | }); | 515 | }); |
| 506 | 516 | ||
| 507 | return yield* sourceStore.persistSource({ | 517 | return yield* sourceStore.persistSource({ |
| @@ -512,7 +522,7 @@ const updateSourceStatus = Effect.fn("source.status.update")((sourceStore: Runti · 4 unmodified lines | |||
| 512 | importAuth: input.importAuth ?? latest.importAuth, | 522 | importAuth: input.importAuth ?? latest.importAuth, |
| 513 | updatedAt: Date.now(), | 523 | updatedAt: Date.now(), |
| 514 | }, { | 524 | }, { |
| 515 | actorAccountId: input.actorAccountId, | 525 | actorScopeId: input.actorScopeId, |
| 516 | }); | 526 | }); |
| 517 | }).pipe( | 527 | }).pipe( |
| 518 | Effect.withSpan("source.status.update", { | 528 | Effect.withSpan("source.status.update", { |
| @@ -564,8 +574,8 @@ export type ExecutorHttpSourceAuthInput = · 45 unmodified lines | |||
| 564 | export type ExecutorAddSourceInput = | 574 | export type ExecutorAddSourceInput = |
| 565 | | { | 575 | | { |
| 566 | kind?: "mcp"; | 576 | kind?: "mcp"; |
| 567 | workspaceId: WorkspaceId; | 577 | scopeId: ScopeId; |
| 568 | actorAccountId?: AccountId | null; | 578 | actorScopeId?: ScopeId | null; |
| 569 | executionId: SourceAuthSession["executionId"]; | 579 | executionId: SourceAuthSession["executionId"]; |
| 570 | interactionId: SourceAuthSession["interactionId"]; | 580 | interactionId: SourceAuthSession["interactionId"]; |
| 571 | endpoint?: string | null; | 581 | endpoint?: string | null; |
| @@ -581,8 +591,8 @@ export type ExecutorAddSourceInput = · 9 unmodified lines | |||
| 581 | } | 591 | } |
| 582 | | { | 592 | | { |
| 583 | kind: "openapi"; | 593 | kind: "openapi"; |
| 584 | workspaceId: WorkspaceId; | 594 | scopeId: ScopeId; |
| 585 | actorAccountId?: AccountId | null; | 595 | actorScopeId?: ScopeId | null; |
| 586 | executionId: SourceAuthSession["executionId"]; | 596 | executionId: SourceAuthSession["executionId"]; |
| 587 | interactionId: SourceAuthSession["interactionId"]; | 597 | interactionId: SourceAuthSession["interactionId"]; |
| 588 | endpoint: string; | 598 | endpoint: string; |
| @@ -595,8 +605,8 @@ export type ExecutorAddSourceInput = · 6 unmodified lines | |||
| 595 | } | 605 | } |
| 596 | | { | 606 | | { |
| 597 | kind: "graphql"; | 607 | kind: "graphql"; |
| 598 | workspaceId: WorkspaceId; | 608 | scopeId: ScopeId; |
| 599 | actorAccountId?: AccountId | null; | 609 | actorScopeId?: ScopeId | null; |
| 600 | executionId: SourceAuthSession["executionId"]; | 610 | executionId: SourceAuthSession["executionId"]; |
| 601 | interactionId: SourceAuthSession["interactionId"]; | 611 | interactionId: SourceAuthSession["interactionId"]; |
| 602 | endpoint: string; | 612 | endpoint: string; |
| @@ -608,15 +618,15 @@ export type ExecutorAddSourceInput = · 5 unmodified lines | |||
| 608 | } | 618 | } |
| 609 | | { | 619 | | { |
| 610 | kind: "google_discovery"; | 620 | kind: "google_discovery"; |
| 611 | workspaceId: WorkspaceId; | 621 | scopeId: ScopeId; |
| 612 | actorAccountId?: AccountId | null; | 622 | actorScopeId?: ScopeId | null; |
| 613 | executionId: SourceAuthSession["executionId"]; | 623 | executionId: SourceAuthSession["executionId"]; |
| 614 | interactionId: SourceAuthSession["interactionId"]; | 624 | interactionId: SourceAuthSession["interactionId"]; |
| 615 | service: string; | 625 | service: string; |
| 616 | version: string; | 626 | version: string; |
| 617 | discoveryUrl?: string | null; | 627 | discoveryUrl?: string | null; |
| 618 | scopes?: ReadonlyArray<string> | null; | 628 | scopes?: ReadonlyArray<string> | null; |
| 619 | workspaceOauthClientId?: WorkspaceOauthClient["id"] | null; | 629 | scopeOauthClientId?: ScopeOauthClient["id"] | null; |
| 620 | oauthClient?: SourceOauthClientInput | null; | 630 | oauthClient?: SourceOauthClientInput | null; |
| 621 | name?: string | null; | 631 | name?: string | null; |
| 622 | namespace?: string | null; | 632 | namespace?: string | null; |
| @@ -641,8 +651,8 @@ export type ExecutorMcpSourceInput = Exclude< · 18 unmodified lines | |||
| 641 | >; | 651 | >; |
| 642 | 652 | ||
| 643 | export type ConnectMcpSourceInput = { | 653 | export type ConnectMcpSourceInput = { |
| 644 | workspaceId: WorkspaceId; | 654 | scopeId: ScopeId; |
| 645 | actorAccountId?: AccountId | null; | 655 | actorScopeId?: ScopeId | null; |
| 646 | sourceId?: Source["id"] | null; | 656 | sourceId?: Source["id"] | null; |
| 647 | endpoint?: string | null; | 657 | endpoint?: string | null; |
| 648 | name?: string | null; | 658 | name?: string | null; |
| @@ -659,11 +669,11 @@ export type ConnectMcpSourceInput = { · 10 unmodified lines | |||
| 659 | }; | 669 | }; |
| 660 | 670 | ||
| 661 | export type ConnectGoogleDiscoveryBatchInput = { | 671 | export type ConnectGoogleDiscoveryBatchInput = { |
| 662 | workspaceId: WorkspaceId; | 672 | scopeId: ScopeId; |
| 663 | actorAccountId?: AccountId | null; | 673 | actorScopeId?: ScopeId | null; |
| 664 | executionId: SourceAuthSession["executionId"]; | 674 | executionId: SourceAuthSession["executionId"]; |
| 665 | interactionId: SourceAuthSession["interactionId"]; | 675 | interactionId: SourceAuthSession["interactionId"]; |
| 666 | workspaceOauthClientId: WorkspaceOauthClient["id"]; | 676 | scopeOauthClientId: ScopeOauthClient["id"]; |
| 667 | sources: ReadonlyArray<{ | 677 | sources: ReadonlyArray<{ |
| 668 | service: string; | 678 | service: string; |
| 669 | version: string; | 679 | version: string; |
| @@ -687,8 +697,8 @@ export type ConnectGoogleDiscoveryBatchResult = { · 17 unmodified lines | |||
| 687 | } | null; | 697 | } | null; |
| 688 | }; | 698 | }; |
| 689 | 699 | ||
| 690 | export type CreateWorkspaceOauthClientInput = { | 700 | export type CreateScopeOauthClientInput = { |
| 691 | workspaceId: WorkspaceId; | 701 | scopeId: ScopeId; |
| 692 | providerKey: string; | 702 | providerKey: string; |
| 693 | label?: string | null; | 703 | label?: string | null; |
| 694 | oauthClient: SourceOauthClientInput; | 704 | oauthClient: SourceOauthClientInput; |
| @@ -707,8 +717,8 @@ export type SourceOAuthProviderInput = { · 12 unmodified lines | |||
| 707 | }; | 717 | }; |
| 708 | 718 | ||
| 709 | export type StartSourceOAuthSessionInput = { | 719 | export type StartSourceOAuthSessionInput = { |
| 710 | workspaceId: WorkspaceId; | 720 | scopeId: ScopeId; |
| 711 | actorAccountId?: AccountId | null; | 721 | actorScopeId?: ScopeId | null; |
| 712 | provider: SourceOAuthProviderInput; | 722 | provider: SourceOAuthProviderInput; |
| 713 | baseUrl?: string | null; | 723 | baseUrl?: string | null; |
| 714 | displayName?: string | null; | 724 | displayName?: string | null; |
| @@ -928,11 +938,11 @@ type ResolvedSourceOauthClient = { · 213 unmodified lines | |||
| 928 | providerKey: string; | 938 | providerKey: string; |
| 929 | clientId: string; | 939 | clientId: string; |
| 930 | clientSecret: SecretRef | null; | 940 | clientSecret: SecretRef | null; |
| 931 | redirectMode: WorkspaceSourceOauthClientRedirectMode; | 941 | redirectMode: ScopedSourceOauthClientRedirectMode; |
| 932 | }; | 942 | }; |
| 933 | 943 | ||
| 934 | type ResolvedWorkspaceOauthClient = ResolvedSourceOauthClient & { | 944 | type ResolvedScopeOauthClient = ResolvedSourceOauthClient & { |
| 935 | id: WorkspaceOauthClient["id"]; | 945 | id: ScopeOauthClient["id"]; |
| 936 | label: string | null; | 946 | label: string | null; |
| 937 | }; | 947 | }; |
| 938 | 948 | ||
| @@ -954,22 +964,22 @@ type RuntimeProviderAuthResult = · 15 unmodified lines | |||
| 954 | authorizationUrl: string; | 964 | authorizationUrl: string; |
| 955 | }; | 965 | }; |
| 956 | 966 | ||
| 957 | const decodeWorkspaceSourceOauthClientMetadataOption = Schema.decodeUnknownOption( | 967 | const decodeScopedSourceOauthClientMetadataOption = Schema.decodeUnknownOption( |
| 958 | WorkspaceSourceOauthClientMetadataJsonSchema, | 968 | ScopedSourceOauthClientMetadataJsonSchema, |
| 959 | ); | 969 | ); |
| 960 | 970 | ||
| 961 | const encodeWorkspaceSourceOauthClientMetadataJson = Schema.encodeSync( | 971 | const encodeScopedSourceOauthClientMetadataJson = Schema.encodeSync( |
| 962 | WorkspaceSourceOauthClientMetadataJsonSchema, | 972 | ScopedSourceOauthClientMetadataJsonSchema, |
| 963 | ); | 973 | ); |
| 964 | 974 | ||
| 965 | const sourceOauthClientRedirectMode = (client: { | 975 | const sourceOauthClientRedirectMode = (client: { |
| 966 | clientMetadataJson: string | null; | 976 | clientMetadataJson: string | null; |
| 967 | }): WorkspaceSourceOauthClientRedirectMode => { | 977 | }): ScopedSourceOauthClientRedirectMode => { |
| 968 | if (client.clientMetadataJson === null) { | 978 | if (client.clientMetadataJson === null) { |
| 969 | return "app_callback"; | 979 | return "app_callback"; |
| 970 | } | 980 | } |
| 971 | 981 | ||
| 972 | const decoded = decodeWorkspaceSourceOauthClientMetadataOption( | 982 | const decoded = decodeScopedSourceOauthClientMetadataOption( |
| 973 | client.clientMetadataJson, | 983 | client.clientMetadataJson, |
| 974 | ); | 984 | ); |
| 975 | if (Option.isNone(decoded)) { | 985 | if (Option.isNone(decoded)) { |
| @@ -1009,8 +1019,8 @@ const upsertSourceOauthClient = (input: { · 33 unmodified lines | |||
| 1009 | return yield* runtimeEffectError("sources/source-auth-service", `Source ${input.source.id} does not support OAuth client configuration`); | 1019 | return yield* runtimeEffectError("sources/source-auth-service", `Source ${input.source.id} does not support OAuth client configuration`); |
| 1010 | } | 1020 | } |
| 1011 | 1021 | ||
| 1012 | const existing = yield* input.executorState.sourceOauthClients.getByWorkspaceSourceAndProvider({ | 1022 | const existing = yield* input.executorState.sourceOauthClients.getByScopeSourceAndProvider({ |
| 1013 | workspaceId: input.source.workspaceId, | 1023 | scopeId: input.source.scopeId, |
| 1014 | sourceId: input.source.id, | 1024 | sourceId: input.source.id, |
| 1015 | providerKey: setupConfig.providerKey, | 1025 | providerKey: setupConfig.providerKey, |
| 1016 | }); | 1026 | }); |
| @@ -1029,18 +1039,18 @@ const upsertSourceOauthClient = (input: { · 12 unmodified lines | |||
| 1029 | const now = Date.now(); | 1039 | const now = Date.now(); |
| 1030 | const clientId = Option.isSome(existing) | 1040 | const clientId = Option.isSome(existing) |
| 1031 | ? existing.value.id | 1041 | ? existing.value.id |
| 1032 | : WorkspaceSourceOauthClientIdSchema.make( | 1042 | : ScopedSourceOauthClientIdSchema.make( |
| 1033 | `src_oauth_client_${crypto.randomUUID()}`, | 1043 | `src_oauth_client_${crypto.randomUUID()}`, |
| 1034 | ); | 1044 | ); |
| 1035 | yield* input.executorState.sourceOauthClients.upsert({ | 1045 | yield* input.executorState.sourceOauthClients.upsert({ |
| 1036 | id: clientId, | 1046 | id: clientId, |
| 1037 | workspaceId: input.source.workspaceId, | 1047 | scopeId: input.source.scopeId, |
| 1038 | sourceId: input.source.id, | 1048 | sourceId: input.source.id, |
| 1039 | providerKey: setupConfig.providerKey, | 1049 | providerKey: setupConfig.providerKey, |
| 1040 | clientId: normalizedOauthClient.clientId, | 1050 | clientId: normalizedOauthClient.clientId, |
| 1041 | clientSecretProviderId: clientSecretRef?.providerId ?? null, | 1051 | clientSecretProviderId: clientSecretRef?.providerId ?? null, |
| 1042 | clientSecretHandle: clientSecretRef?.handle ?? null, | 1052 | clientSecretHandle: clientSecretRef?.handle ?? null, |
| 1043 | clientMetadataJson: encodeWorkspaceSourceOauthClientMetadataJson({ | 1053 | clientMetadataJson: encodeScopedSourceOauthClientMetadataJson({ |
| 1044 | redirectMode: normalizedOauthClient.redirectMode ?? "app_callback", | 1054 | redirectMode: normalizedOauthClient.redirectMode ?? "app_callback", |
| 1045 | }), | 1055 | }), |
| 1046 | createdAt: Option.isSome(existing) ? existing.value.createdAt : now, | 1056 | createdAt: Option.isSome(existing) ? existing.value.createdAt : now, |
| @@ -1084,8 +1094,8 @@ const resolveExistingSourceOauthClient = (input: { · 37 unmodified lines | |||
| 1084 | return null; | 1094 | return null; |
| 1085 | } | 1095 | } |
| 1086 | 1096 | ||
| 1087 | const existing = yield* input.executorState.sourceOauthClients.getByWorkspaceSourceAndProvider({ | 1097 | const existing = yield* input.executorState.sourceOauthClients.getByScopeSourceAndProvider({ |
| 1088 | workspaceId: input.source.workspaceId, | 1098 | scopeId: input.source.scopeId, |
| 1089 | sourceId: input.source.id, | 1099 | sourceId: input.source.id, |
| 1090 | providerKey: setupConfig.providerKey, | 1100 | providerKey: setupConfig.providerKey, |
| 1091 | }); | 1101 | }); |
| @@ -1101,9 +1111,9 @@ const resolveExistingSourceOauthClient = (input: { · 9 unmodified lines | |||
| 1101 | }; | 1111 | }; |
| 1102 | }); | 1112 | }); |
| 1103 | 1113 | ||
| 1104 | const createWorkspaceOauthClient = (input: { | 1114 | const createScopeOauthClient = (input: { |
| 1105 | executorState: ExecutorStateStoreShape; | 1115 | executorState: ExecutorStateStoreShape; |
| 1106 | workspaceId: WorkspaceId; | 1116 | scopeId: ScopeId; |
| 1107 | providerKey: string; | 1117 | providerKey: string; |
| 1108 | oauthClient: SourceOauthClientInput; | 1118 | oauthClient: SourceOauthClientInput; |
| 1109 | label?: string | null; | 1119 | label?: string | null; |
| @@ -1111,7 +1121,7 @@ const createWorkspaceOauthClient = (input: { · 1 unmodified line | |||
| 1111 | input: SourceOauthClientInput, | 1121 | input: SourceOauthClientInput, |
| 1112 | ) => Effect.Effect<SourceOauthClientInput, Error, never>; | 1122 | ) => Effect.Effect<SourceOauthClientInput, Error, never>; |
| 1113 | storeSecretMaterial: StoreSecretMaterial; | 1123 | storeSecretMaterial: StoreSecretMaterial; |
| 1114 | }): Effect.Effect<ResolvedWorkspaceOauthClient, Error, never> => | 1124 | }): Effect.Effect<ResolvedScopeOauthClient, Error, never> => |
| 1115 | Effect.gen(function* () { | 1125 | Effect.gen(function* () { |
| 1116 | const normalizedOauthClient = input.normalizeOauthClient | 1126 | const normalizedOauthClient = input.normalizeOauthClient |
| 1117 | ? yield* input.normalizeOauthClient(input.oauthClient) | 1127 | ? yield* input.normalizeOauthClient(input.oauthClient) |
| @@ -1123,19 +1133,19 @@ const createWorkspaceOauthClient = (input: { · 5 unmodified lines | |||
| 1123 | }) | 1133 | }) |
| 1124 | : null; | 1134 | : null; |
| 1125 | const now = Date.now(); | 1135 | const now = Date.now(); |
| 1126 | const id = WorkspaceOauthClientIdSchema.make( | 1136 | const id = ScopeOauthClientIdSchema.make( |
| 1127 | `ws_oauth_client_${crypto.randomUUID()}`, | 1137 | `ws_oauth_client_${crypto.randomUUID()}`, |
| 1128 | ); | 1138 | ); |
| 1129 | 1139 | ||
| 1130 | yield* input.executorState.workspaceOauthClients.upsert({ | 1140 | yield* input.executorState.scopeOauthClients.upsert({ |
| 1131 | id, | 1141 | id, |
| 1132 | workspaceId: input.workspaceId, | 1142 | scopeId: input.scopeId, |
| 1133 | providerKey: input.providerKey, | 1143 | providerKey: input.providerKey, |
| 1134 | label: trimOrNull(input.label) ?? null, | 1144 | label: trimOrNull(input.label) ?? null, |
| 1135 | clientId: normalizedOauthClient.clientId, | 1145 | clientId: normalizedOauthClient.clientId, |
| 1136 | clientSecretProviderId: clientSecretRef?.providerId ?? null, | 1146 | clientSecretProviderId: clientSecretRef?.providerId ?? null, |
| 1137 | clientSecretHandle: clientSecretRef?.handle ?? null, | 1147 | clientSecretHandle: clientSecretRef?.handle ?? null, |
| 1138 | clientMetadataJson: encodeWorkspaceSourceOauthClientMetadataJson({ | 1148 | clientMetadataJson: encodeScopedSourceOauthClientMetadataJson({ |
| 1139 | redirectMode: normalizedOauthClient.redirectMode ?? "app_callback", | 1149 | redirectMode: normalizedOauthClient.redirectMode ?? "app_callback", |
| 1140 | }), | 1150 | }), |
| 1141 | createdAt: now, | 1151 | createdAt: now, |
| @@ -1152,23 +1162,28 @@ const createWorkspaceOauthClient = (input: { · 10 unmodified lines | |||
| 1152 | }; | 1162 | }; |
| 1153 | }); | 1163 | }); |
| 1154 | 1164 | ||
| 1155 | const resolveWorkspaceOauthClientById = (input: { | 1165 | const resolveScopeOauthClientById = (input: { |
| 1156 | executorState: ExecutorStateStoreShape; | 1166 | executorState: ExecutorStateStoreShape; |
| 1157 | workspaceId: WorkspaceId; | 1167 | scopeId: ScopeId; |
| 1158 | oauthClientId: WorkspaceOauthClient["id"]; | 1168 | oauthClientId: ScopeOauthClient["id"]; |
| 1159 | providerKey: string; | 1169 | providerKey: string; |
| 1160 | }): Effect.Effect<ResolvedWorkspaceOauthClient | null, Error, never> => | 1170 | localScopeState?: RuntimeLocalScopeState; |
| 1171 | }): Effect.Effect<ResolvedScopeOauthClient | null, Error, never> => | ||
| 1161 | Effect.gen(function* () { | 1172 | Effect.gen(function* () { |
| 1162 | const existing = yield* input.executorState.workspaceOauthClients.getById(input.oauthClientId); | 1173 | const existing = yield* input.executorState.scopeOauthClients.getById(input.oauthClientId); |
| 1163 | if (Option.isNone(existing)) { | 1174 | if (Option.isNone(existing)) { |
| 1164 | return null; | 1175 | return null; |
| 1165 | } | 1176 | } |
| 1166 | 1177 | ||
| 1178 | const allowedScopeIds = resolvedScopeSearchOrder({ | ||
| 1179 | scopeId: input.scopeId, | ||
| 1180 | localScopeState: input.localScopeState, | ||
| 1181 | }); | ||
| 1167 | if ( | 1182 | if ( |
| 1168 | existing.value.workspaceId !== input.workspaceId | 1183 | !allowedScopeIds.includes(existing.value.scopeId) |
| 1169 | || existing.value.providerKey !== input.providerKey | 1184 | || existing.value.providerKey !== input.providerKey |
| 1170 | ) { | 1185 | ) { |
| 1171 | return yield* runtimeEffectError("sources/source-auth-service", `Workspace OAuth client ${input.oauthClientId} is not valid for ${input.providerKey}`); | 1186 | return yield* runtimeEffectError("sources/source-auth-service", `Scope OAuth client ${input.oauthClientId} is not valid for ${input.providerKey}`); |
| 1172 | } | 1187 | } |
| 1173 | 1188 | ||
| 1174 | return { | 1189 | return { |
| @@ -1192,6 +1207,25 @@ const providerGrantCoversScopes = ( · 17 unmodified lines | |||
| 1192 | const normalizeScopes = (scopes: ReadonlyArray<string>): ReadonlyArray<string> => | 1207 | const normalizeScopes = (scopes: ReadonlyArray<string>): ReadonlyArray<string> => |
| 1193 | [...new Set(scopes.map((scope) => scope.trim()).filter((scope) => scope.length > 0))]; | 1208 | [...new Set(scopes.map((scope) => scope.trim()).filter((scope) => scope.length > 0))]; |
| 1194 | 1209 | ||
| 1210 | const resolvedScopeSearchOrder = (input: { | ||
| 1211 | scopeId: ScopeId; | ||
| 1212 | localScopeState?: RuntimeLocalScopeState; | ||
| 1213 | }): ReadonlyArray<ScopeId> => { | ||
| 1214 | const localScopeState = input.localScopeState; | ||
| 1215 | if (!localScopeState) { | ||
| 1216 | return [input.scopeId]; | ||
| 1217 | } | ||
| 1218 | |||
| 1219 | if (localScopeState.installation.scopeId !== input.scopeId) { | ||
| 1220 | return [input.scopeId]; | ||
| 1221 | } | ||
| 1222 | |||
| 1223 | return [...new Set([ | ||
| 1224 | input.scopeId, | ||
| 1225 | ...localScopeState.installation.resolutionScopeIds, | ||
| 1226 | ])]; | ||
| 1227 | }; | ||
| 1228 | |||
| 1195 | const authorizationParamsMatch = ( | 1229 | const authorizationParamsMatch = ( |
| 1196 | left: SourceAdapterOauth2SetupConfig["authorizationParams"], | 1230 | left: SourceAdapterOauth2SetupConfig["authorizationParams"], |
| 1197 | right: SourceAdapterOauth2SetupConfig["authorizationParams"], | 1231 | right: SourceAdapterOauth2SetupConfig["authorizationParams"], |
| @@ -1272,34 +1306,44 @@ const mergeRuntimeProviderAuthSetupConfig = ( · 74 unmodified lines | |||
| 1272 | 1306 | ||
| 1273 | const findReusableProviderGrant = (input: { | 1307 | const findReusableProviderGrant = (input: { |
| 1274 | executorState: ExecutorStateStoreShape; | 1308 | executorState: ExecutorStateStoreShape; |
| 1275 | workspaceId: WorkspaceId; | 1309 | scopeId: ScopeId; |
| 1276 | actorAccountId?: AccountId | null; | 1310 | actorScopeId?: ScopeId | null; |
| 1277 | providerKey: string; | 1311 | providerKey: string; |
| 1278 | oauthClientId: WorkspaceOauthClient["id"]; | 1312 | oauthClientId: ScopeOauthClient["id"]; |
| 1279 | requiredScopes: ReadonlyArray<string>; | 1313 | requiredScopes: ReadonlyArray<string>; |
| 1314 | localScopeState?: RuntimeLocalScopeState; | ||
| 1280 | }): Effect.Effect<import("effect/Option").Option<import("#schema").ProviderAuthGrant>, Error, never> => | 1315 | }): Effect.Effect<import("effect/Option").Option<import("#schema").ProviderAuthGrant>, Error, never> => |
| 1281 | Effect.map( | 1316 | Effect.gen(function* () { |
| 1282 | input.executorState.providerAuthGrants.listByWorkspaceActorAndProvider({ | 1317 | const scopeIds = resolvedScopeSearchOrder({ |
| 1283 | workspaceId: input.workspaceId, | 1318 | scopeId: input.scopeId, |
| 1284 | actorAccountId: input.actorAccountId ?? null, | 1319 | localScopeState: input.localScopeState, |
| 1285 | providerKey: input.providerKey, | 1320 | }); |
| 1286 | }), | 1321 | |
| 1287 | (grants) => | 1322 | for (const candidateScopeId of scopeIds) { |
| 1288 | Option.fromNullable( | 1323 | const grants = yield* input.executorState.providerAuthGrants.listByScopeActorAndProvider({ |
| 1289 | grants.find( | 1324 | scopeId: candidateScopeId, |
| 1290 | (grant) => | 1325 | actorScopeId: input.actorScopeId ?? null, |
| 1291 | grant.oauthClientId === input.oauthClientId | 1326 | providerKey: input.providerKey, |
| 1292 | && providerGrantCoversScopes(grant.grantedScopes, input.requiredScopes), | 1327 | }); |
| 1293 | ), | 1328 | const matchingGrant = grants.find( |
| 1294 | ), | 1329 | (grant) => |
| 1295 | ); | 1330 | grant.oauthClientId === input.oauthClientId |
| 1331 | && providerGrantCoversScopes(grant.grantedScopes, input.requiredScopes), | ||
| 1332 | ); | ||
| 1333 | if (matchingGrant) { | ||
| 1334 | return Option.some(matchingGrant); | ||
| 1335 | } | ||
| 1336 | } | ||
| 1337 | |||
| 1338 | return Option.none(); | ||
| 1339 | }); | ||
| 1296 | 1340 | ||
| 1297 | const upsertProviderAuthGrant = (input: { | 1341 | const upsertProviderAuthGrant = (input: { |
| 1298 | executorState: ExecutorStateStoreShape; | 1342 | executorState: ExecutorStateStoreShape; |
| 1299 | workspaceId: WorkspaceId; | 1343 | scopeId: ScopeId; |
| 1300 | actorAccountId?: AccountId | null; | 1344 | actorScopeId?: ScopeId | null; |
| 1301 | providerKey: string; | 1345 | providerKey: string; |
| 1302 | oauthClientId: WorkspaceOauthClient["id"]; | 1346 | oauthClientId: ScopeOauthClient["id"]; |
| 1303 | tokenEndpoint: string; | 1347 | tokenEndpoint: string; |
| 1304 | clientAuthentication: "none" | "client_secret_post"; | 1348 | clientAuthentication: "none" | "client_secret_post"; |
| 1305 | headerName: string; | 1349 | headerName: string; |
| @@ -1328,8 +1372,8 @@ const upsertProviderAuthGrant = (input: { · 22 unmodified lines | |||
| 1328 | const now = Date.now(); | 1372 | const now = Date.now(); |
| 1329 | const nextGrant = { | 1373 | const nextGrant = { |
| 1330 | id: existingGrant?.id ?? ProviderAuthGrantIdSchema.make(`provider_grant_${crypto.randomUUID()}`), | 1374 | id: existingGrant?.id ?? ProviderAuthGrantIdSchema.make(`provider_grant_${crypto.randomUUID()}`), |
| 1331 | workspaceId: input.workspaceId, | 1375 | scopeId: input.scopeId, |
| 1332 | actorAccountId: input.actorAccountId ?? null, | 1376 | actorScopeId: input.actorScopeId ?? null, |
| 1333 | providerKey: input.providerKey, | 1377 | providerKey: input.providerKey, |
| 1334 | oauthClientId: input.oauthClientId, | 1378 | oauthClientId: input.oauthClientId, |
| 1335 | tokenEndpoint: input.tokenEndpoint, | 1379 | tokenEndpoint: input.tokenEndpoint, |
| @@ -1369,16 +1413,16 @@ const startOauth2PkceSourceCredentialSetup = (input: { · 33 unmodified lines | |||
| 1369 | executorState: ExecutorStateStoreShape; | 1413 | executorState: ExecutorStateStoreShape; |
| 1370 | sourceStore: RuntimeSourceStore; | 1414 | sourceStore: RuntimeSourceStore; |
| 1371 | source: Source; | 1415 | source: Source; |
| 1372 | actorAccountId?: AccountId | null; | 1416 | actorScopeId?: ScopeId | null; |
| 1373 | executionId?: SourceAuthSession["executionId"]; | 1417 | executionId?: SourceAuthSession["executionId"]; |
| 1374 | interactionId?: SourceAuthSession["interactionId"]; | 1418 | interactionId?: SourceAuthSession["interactionId"]; |
| 1375 | baseUrl: string; | 1419 | baseUrl: string; |
| 1376 | redirectModeOverride?: WorkspaceSourceOauthClientRedirectMode; | 1420 | redirectModeOverride?: ScopedSourceOauthClientRedirectMode; |
| 1377 | storeSecretMaterial: StoreSecretMaterial; | 1421 | storeSecretMaterial: StoreSecretMaterial; |
| 1378 | }): Effect.Effect< | 1422 | }): Effect.Effect< |
| 1379 | Extract<ExecutorSourceAddResult, { kind: "oauth_required" }> | null, | 1423 | Extract<ExecutorSourceAddResult, { kind: "oauth_required" }> | null, |
| 1380 | Error, | 1424 | Error, |
| 1381 | WorkspaceStorageServices | 1425 | ScopeStorageServices |
| 1382 | > => | 1426 | > => |
| 1383 | Effect.gen(function* () { | 1427 | Effect.gen(function* () { |
| 1384 | const adapter = getSourceAdapterForSource(input.source); | 1428 | const adapter = getSourceAdapterForSource(input.source); |
| @@ -1404,7 +1448,7 @@ const startOauth2PkceSourceCredentialSetup = (input: { · 19 unmodified lines | |||
| 1404 | const state = crypto.randomUUID(); | 1448 | const state = crypto.randomUUID(); |
| 1405 | const completionUrl = resolveSourceCredentialOauthCompleteUrl({ | 1449 | const completionUrl = resolveSourceCredentialOauthCompleteUrl({ |
| 1406 | baseUrl: input.baseUrl, | 1450 | baseUrl: input.baseUrl, |
| 1407 | workspaceId: input.source.workspaceId, | 1451 | scopeId: input.source.scopeId, |
| 1408 | sourceId: input.source.id, | 1452 | sourceId: input.source.id, |
| 1409 | }); | 1453 | }); |
| 1410 | const redirectMode = input.redirectModeOverride ?? oauthClient.redirectMode; | 1454 | const redirectMode = input.redirectModeOverride ?? oauthClient.redirectMode; |
| @@ -1429,9 +1473,9 @@ const startOauth2PkceSourceCredentialSetup = (input: { · 18 unmodified lines | |||
| 1429 | 1473 | ||
| 1430 | yield* input.executorState.sourceAuthSessions.upsert({ | 1474 | yield* input.executorState.sourceAuthSessions.upsert({ |
| 1431 | id: sessionId, | 1475 | id: sessionId, |
| 1432 | workspaceId: input.source.workspaceId, | 1476 | scopeId: input.source.scopeId, |
| 1433 | sourceId: input.source.id, | 1477 | sourceId: input.source.id, |
| 1434 | actorAccountId: input.actorAccountId ?? null, | 1478 | actorScopeId: input.actorScopeId ?? null, |
| 1435 | credentialSlot: "runtime", | 1479 | credentialSlot: "runtime", |
| 1436 | executionId: input.executionId ?? null, | 1480 | executionId: input.executionId ?? null, |
| 1437 | interactionId: input.interactionId ?? null, | 1481 | interactionId: input.interactionId ?? null, |
| @@ -1463,7 +1507,7 @@ const startOauth2PkceSourceCredentialSetup = (input: { · 25 unmodified lines | |||
| 1463 | }); | 1507 | }); |
| 1464 | 1508 | ||
| 1465 | const authRequiredSource = yield* updateSourceStatus(input.sourceStore, input.source, { | 1509 | const authRequiredSource = yield* updateSourceStatus(input.sourceStore, input.source, { |
| 1466 | actorAccountId: input.actorAccountId, | 1510 | actorScopeId: input.actorScopeId, |
| 1467 | status: "auth_required", | 1511 | status: "auth_required", |
| 1468 | lastError: null, | 1512 | lastError: null, |
| 1469 | }); | 1513 | }); |
| @@ -1486,13 +1530,13 @@ const startOauth2PkceSourceCredentialSetup = (input: { · 16 unmodified lines | |||
| 1486 | const startProviderOauthBatchCredentialSetup = (input: { | 1530 | const startProviderOauthBatchCredentialSetup = (input: { |
| 1487 | executorState: ExecutorStateStoreShape; | 1531 | executorState: ExecutorStateStoreShape; |
| 1488 | sourceStore: RuntimeSourceStore; | 1532 | sourceStore: RuntimeSourceStore; |
| 1489 | workspaceId: WorkspaceId; | 1533 | scopeId: ScopeId; |
| 1490 | actorAccountId?: AccountId | null; | 1534 | actorScopeId?: ScopeId | null; |
| 1491 | executionId?: SourceAuthSession["executionId"]; | 1535 | executionId?: SourceAuthSession["executionId"]; |
| 1492 | interactionId?: SourceAuthSession["interactionId"]; | 1536 | interactionId?: SourceAuthSession["interactionId"]; |
| 1493 | baseUrl: string; | 1537 | baseUrl: string; |
| 1494 | redirectModeOverride?: WorkspaceSourceOauthClientRedirectMode; | 1538 | redirectModeOverride?: ScopedSourceOauthClientRedirectMode; |
| 1495 | workspaceOauthClient: ResolvedWorkspaceOauthClient; | 1539 | scopeOauthClient: ResolvedScopeOauthClient; |
| 1496 | setupConfig: SourceAdapterOauth2SetupConfig; | 1540 | setupConfig: SourceAdapterOauth2SetupConfig; |
| 1497 | targetSources: ReadonlyArray<{ | 1541 | targetSources: ReadonlyArray<{ |
| 1498 | source: Source; | 1542 | source: Source; |
| @@ -1502,7 +1546,7 @@ const startProviderOauthBatchCredentialSetup = (input: { · 3 unmodified lines | |||
| 1502 | sessionId: SourceAuthSession["id"]; | 1546 | sessionId: SourceAuthSession["id"]; |
| 1503 | authorizationUrl: string; | 1547 | authorizationUrl: string; |
| 1504 | source: Source; | 1548 | source: Source; |
| 1505 | }, Error, WorkspaceStorageServices> => | 1549 | }, Error, ScopeStorageServices> => |
| 1506 | Effect.gen(function* () { | 1550 | Effect.gen(function* () { |
| 1507 | if (input.targetSources.length === 0) { | 1551 | if (input.targetSources.length === 0) { |
| 1508 | return yield* runtimeEffectError("sources/source-auth-service", "Provider OAuth setup requires at least one target source"); | 1552 | return yield* runtimeEffectError("sources/source-auth-service", "Provider OAuth setup requires at least one target source"); |
| @@ -1512,9 +1556,9 @@ const startProviderOauthBatchCredentialSetup = (input: { · 3 unmodified lines | |||
| 1512 | const state = crypto.randomUUID(); | 1556 | const state = crypto.randomUUID(); |
| 1513 | const completionUrl = resolveWorkspaceProviderOauthCompleteUrl({ | 1557 | const completionUrl = resolveWorkspaceProviderOauthCompleteUrl({ |
| 1514 | baseUrl: input.baseUrl, | 1558 | baseUrl: input.baseUrl, |
| 1515 | workspaceId: input.workspaceId, | 1559 | scopeId: input.scopeId, |
| 1516 | }); | 1560 | }); |
| 1517 | const redirectMode = input.redirectModeOverride ?? input.workspaceOauthClient.redirectMode; | 1561 | const redirectMode = input.redirectModeOverride ?? input.scopeOauthClient.redirectMode; |
| 1518 | const redirectServer = redirectMode === "loopback" | 1562 | const redirectServer = redirectMode === "loopback" |
| 1519 | ? yield* startOauthLoopbackRedirectServer({ | 1563 | ? yield* startOauthLoopbackRedirectServer({ |
| 1520 | completionUrl, | 1564 | completionUrl, |
| @@ -1526,7 +1570,7 @@ const startProviderOauthBatchCredentialSetup = (input: { · 5 unmodified lines | |||
| 1526 | return yield* Effect.gen(function* () { | 1570 | return yield* Effect.gen(function* () { |
| 1527 | const authorizationUrl = buildOAuth2AuthorizationUrl({ | 1571 | const authorizationUrl = buildOAuth2AuthorizationUrl({ |
| 1528 | authorizationEndpoint: input.setupConfig.authorizationEndpoint, | 1572 | authorizationEndpoint: input.setupConfig.authorizationEndpoint, |
| 1529 | clientId: input.workspaceOauthClient.clientId, | 1573 | clientId: input.scopeOauthClient.clientId, |
| 1530 | redirectUri, | 1574 | redirectUri, |
| 1531 | scopes: [...normalizeScopes(input.setupConfig.scopes)], | 1575 | scopes: [...normalizeScopes(input.setupConfig.scopes)], |
| 1532 | state, | 1576 | state, |
| @@ -1537,9 +1581,9 @@ const startProviderOauthBatchCredentialSetup = (input: { · 4 unmodified lines | |||
| 1537 | 1581 | ||
| 1538 | yield* input.executorState.sourceAuthSessions.upsert({ | 1582 | yield* input.executorState.sourceAuthSessions.upsert({ |
| 1539 | id: sessionId, | 1583 | id: sessionId, |
| 1540 | workspaceId: input.workspaceId, | 1584 | scopeId: input.scopeId, |
| 1541 | sourceId: SourceIdSchema.make(`oauth_provider_${crypto.randomUUID()}`), | 1585 | sourceId: SourceIdSchema.make(`oauth_provider_${crypto.randomUUID()}`), |
| 1542 | actorAccountId: input.actorAccountId ?? null, | 1586 | actorScopeId: input.actorScopeId ?? null, |
| 1543 | credentialSlot: "runtime", | 1587 | credentialSlot: "runtime", |
| 1544 | executionId: input.executionId ?? null, | 1588 | executionId: input.executionId ?? null, |
| 1545 | interactionId: input.interactionId ?? null, | 1589 | interactionId: input.interactionId ?? null, |
| @@ -1552,7 +1596,7 @@ const startProviderOauthBatchCredentialSetup = (input: { · 6 unmodified lines | |||
| 1552 | authorizationEndpoint: input.setupConfig.authorizationEndpoint, | 1596 | authorizationEndpoint: input.setupConfig.authorizationEndpoint, |
| 1553 | tokenEndpoint: input.setupConfig.tokenEndpoint, | 1597 | tokenEndpoint: input.setupConfig.tokenEndpoint, |
| 1554 | redirectUri, | 1598 | redirectUri, |
| 1555 | oauthClientId: input.workspaceOauthClient.id, | 1599 | oauthClientId: input.scopeOauthClient.id, |
| 1556 | clientAuthentication: input.setupConfig.clientAuthentication, | 1600 | clientAuthentication: input.setupConfig.clientAuthentication, |
| 1557 | scopes: [...normalizeScopes(input.setupConfig.scopes)], | 1601 | scopes: [...normalizeScopes(input.setupConfig.scopes)], |
| 1558 | headerName: input.setupConfig.headerName, | 1602 | headerName: input.setupConfig.headerName, |
| @@ -1577,7 +1621,7 @@ const startProviderOauthBatchCredentialSetup = (input: { · 18 unmodified lines | |||
| 1577 | input.sourceStore, | 1621 | input.sourceStore, |
| 1578 | input.targetSources[0]!.source, | 1622 | input.targetSources[0]!.source, |
| 1579 | { | 1623 | { |
| 1580 | actorAccountId: input.actorAccountId, | 1624 | actorScopeId: input.actorScopeId, |
| 1581 | status: "auth_required", | 1625 | status: "auth_required", |
| 1582 | lastError: null, | 1626 | lastError: null, |
| 1583 | }, | 1627 | }, |
| @@ -1587,7 +1631,7 @@ const startProviderOauthBatchCredentialSetup = (input: { · 3 unmodified lines | |||
| 1587 | input.targetSources.slice(1), | 1631 | input.targetSources.slice(1), |
| 1588 | (target) => | 1632 | (target) => |
| 1589 | updateSourceStatus(input.sourceStore, target.source, { | 1633 | updateSourceStatus(input.sourceStore, target.source, { |
| 1590 | actorAccountId: input.actorAccountId, | 1634 | actorScopeId: input.actorScopeId, |
| 1591 | status: "auth_required", | 1635 | status: "auth_required", |
| 1592 | lastError: null, | 1636 | lastError: null, |
| 1593 | }).pipe(Effect.asVoid), | 1637 | }).pipe(Effect.asVoid), |
| @@ -1612,31 +1656,33 @@ const connectSourcesWithProviderRuntimeAuth = (input: { · 18 unmodified lines | |||
| 1612 | executorState: ExecutorStateStoreShape; | 1656 | executorState: ExecutorStateStoreShape; |
| 1613 | sourceStore: RuntimeSourceStore; | 1657 | sourceStore: RuntimeSourceStore; |
| 1614 | sourceCatalogSync: RuntimeSourceCatalogSyncShape; | 1658 | sourceCatalogSync: RuntimeSourceCatalogSyncShape; |
| 1615 | workspaceId: WorkspaceId; | 1659 | scopeId: ScopeId; |
| 1616 | actorAccountId?: AccountId | null; | 1660 | actorScopeId?: ScopeId | null; |
| 1617 | executionId?: SourceAuthSession["executionId"]; | 1661 | executionId?: SourceAuthSession["executionId"]; |
| 1618 | interactionId?: SourceAuthSession["interactionId"]; | 1662 | interactionId?: SourceAuthSession["interactionId"]; |
| 1619 | baseUrl?: string | null; | 1663 | baseUrl?: string | null; |
| 1620 | getLocalServerBaseUrl?: () => string | undefined; | 1664 | getLocalServerBaseUrl?: () => string | undefined; |
| 1621 | workspaceOauthClient: ResolvedWorkspaceOauthClient; | 1665 | scopeOauthClient: ResolvedScopeOauthClient; |
| 1622 | targets: ReadonlyArray<RuntimeProviderAuthTarget>; | 1666 | targets: ReadonlyArray<RuntimeProviderAuthTarget>; |
| 1623 | }): Effect.Effect<RuntimeProviderAuthResult, Error, WorkspaceStorageServices> => | 1667 | localScopeState?: RuntimeLocalScopeState; |
| 1668 | }): Effect.Effect<RuntimeProviderAuthResult, Error, ScopeStorageServices> => | ||
| 1624 | Effect.gen(function* () { | 1669 | Effect.gen(function* () { |
| 1625 | const setupConfig = yield* mergeRuntimeProviderAuthSetupConfig(input.targets); | 1670 | const setupConfig = yield* mergeRuntimeProviderAuthSetupConfig(input.targets); |
| 1626 | const reusableGrant = yield* findReusableProviderGrant({ | 1671 | const reusableGrant = yield* findReusableProviderGrant({ |
| 1627 | executorState: input.executorState, | 1672 | executorState: input.executorState, |
| 1628 | workspaceId: input.workspaceId, | 1673 | scopeId: input.scopeId, |
| 1629 | actorAccountId: input.actorAccountId, | 1674 | actorScopeId: input.actorScopeId, |
| 1630 | providerKey: setupConfig.providerKey, | 1675 | providerKey: setupConfig.providerKey, |
| 1631 | oauthClientId: input.workspaceOauthClient.id, | 1676 | oauthClientId: input.scopeOauthClient.id, |
| 1632 | requiredScopes: setupConfig.scopes, | 1677 | requiredScopes: setupConfig.scopes, |
| 1678 | localScopeState: input.localScopeState, | ||
| 1633 | }); | 1679 | }); |
| 1634 | 1680 | ||
| 1635 | if (Option.isSome(reusableGrant)) { | 1681 | if (Option.isSome(reusableGrant)) { |
| 1636 | const connectedSources = yield* attachProviderGrantToSources({ | 1682 | const connectedSources = yield* attachProviderGrantToSources({ |
| 1637 | sourceStore: input.sourceStore, | 1683 | sourceStore: input.sourceStore, |
| 1638 | sourceCatalogSync: input.sourceCatalogSync, | 1684 | sourceCatalogSync: input.sourceCatalogSync, |
| 1639 | actorAccountId: input.actorAccountId, | 1685 | actorScopeId: input.actorScopeId, |
| 1640 | grantId: reusableGrant.value.id, | 1686 | grantId: reusableGrant.value.id, |
| 1641 | providerKey: reusableGrant.value.providerKey, | 1687 | providerKey: reusableGrant.value.providerKey, |
| 1642 | headerName: reusableGrant.value.headerName, | 1688 | headerName: reusableGrant.value.headerName, |
| @@ -1665,13 +1711,13 @@ const connectSourcesWithProviderRuntimeAuth = (input: { · 22 unmodified lines | |||
| 1665 | const oauthRequired = yield* startProviderOauthBatchCredentialSetup({ | 1711 | const oauthRequired = yield* startProviderOauthBatchCredentialSetup({ |
| 1666 | executorState: input.executorState, | 1712 | executorState: input.executorState, |
| 1667 | sourceStore: input.sourceStore, | 1713 | sourceStore: input.sourceStore, |
| 1668 | workspaceId: input.workspaceId, | 1714 | scopeId: input.scopeId, |
| 1669 | actorAccountId: input.actorAccountId, | 1715 | actorScopeId: input.actorScopeId, |
| 1670 | executionId: input.executionId, | 1716 | executionId: input.executionId, |
| 1671 | interactionId: input.interactionId, | 1717 | interactionId: input.interactionId, |
| 1672 | baseUrl, | 1718 | baseUrl, |
| 1673 | redirectModeOverride: requestBaseUrl ? "app_callback" : undefined, | 1719 | redirectModeOverride: requestBaseUrl ? "app_callback" : undefined, |
| 1674 | workspaceOauthClient: input.workspaceOauthClient, | 1720 | scopeOauthClient: input.scopeOauthClient, |
| 1675 | setupConfig, | 1721 | setupConfig, |
| 1676 | targetSources: input.targets.map((target) => ({ | 1722 | targetSources: input.targets.map((target) => ({ |
| 1677 | source: target.source, | 1723 | source: target.source, |
| @@ -1683,9 +1729,9 @@ const connectSourcesWithProviderRuntimeAuth = (input: { · 5 unmodified lines | |||
| 1683 | input.targets, | 1729 | input.targets, |
| 1684 | (target) => | 1730 | (target) => |
| 1685 | input.sourceStore.loadSourceById({ | 1731 | input.sourceStore.loadSourceById({ |
| 1686 | workspaceId: target.source.workspaceId, | 1732 | scopeId: target.source.scopeId, |
| 1687 | sourceId: target.source.id, | 1733 | sourceId: target.source.id, |
| 1688 | actorAccountId: input.actorAccountId, | 1734 | actorScopeId: input.actorScopeId, |
| 1689 | }), | 1735 | }), |
| 1690 | { discard: false }, | 1736 | { discard: false }, |
| 1691 | ); | 1737 | ); |
| @@ -1701,7 +1747,7 @@ const connectSourcesWithProviderRuntimeAuth = (input: { · 9 unmodified lines | |||
| 1701 | const attachProviderGrantToSources = (input: { | 1747 | const attachProviderGrantToSources = (input: { |
| 1702 | sourceStore: RuntimeSourceStore; | 1748 | sourceStore: RuntimeSourceStore; |
| 1703 | sourceCatalogSync: RuntimeSourceCatalogSyncShape; | 1749 | sourceCatalogSync: RuntimeSourceCatalogSyncShape; |
| 1704 | actorAccountId?: AccountId | null; | 1750 | actorScopeId?: ScopeId | null; |
| 1705 | grantId: ProviderAuthGrant["id"]; | 1751 | grantId: ProviderAuthGrant["id"]; |
| 1706 | providerKey: string; | 1752 | providerKey: string; |
| 1707 | headerName: string; | 1753 | headerName: string; |
| @@ -1710,13 +1756,13 @@ const attachProviderGrantToSources = (input: { · 2 unmodified lines | |||
| 1710 | source: Source; | 1756 | source: Source; |
| 1711 | requiredScopes: ReadonlyArray<string>; | 1757 | requiredScopes: ReadonlyArray<string>; |
| 1712 | }>; | 1758 | }>; |
| 1713 | }): Effect.Effect<ReadonlyArray<Source>, Error, WorkspaceStorageServices> => | 1759 | }): Effect.Effect<ReadonlyArray<Source>, Error, ScopeStorageServices> => |
| 1714 | Effect.forEach( | 1760 | Effect.forEach( |
| 1715 | input.targets, | 1761 | input.targets, |
| 1716 | (target) => | 1762 | (target) => |
| 1717 | Effect.gen(function* () { | 1763 | Effect.gen(function* () { |
| 1718 | const connectedSource = yield* updateSourceStatus(input.sourceStore, target.source, { | 1764 | const connectedSource = yield* updateSourceStatus(input.sourceStore, target.source, { |
| 1719 | actorAccountId: input.actorAccountId, | 1765 | actorScopeId: input.actorScopeId, |
| 1720 | status: "connected", | 1766 | status: "connected", |
| 1721 | lastError: null, | 1767 | lastError: null, |
| 1722 | auth: { | 1768 | auth: { |
| @@ -1731,7 +1777,7 @@ const attachProviderGrantToSources = (input: { · 8 unmodified lines | |||
| 1731 | 1777 | ||
| 1732 | yield* input.sourceCatalogSync.sync({ | 1778 | yield* input.sourceCatalogSync.sync({ |
| 1733 | source: connectedSource, | 1779 | source: connectedSource, |
| 1734 | actorAccountId: input.actorAccountId, | 1780 | actorScopeId: input.actorScopeId, |
| 1735 | }); | 1781 | }); |
| 1736 | 1782 | ||
| 1737 | return connectedSource; | 1783 | return connectedSource; |
| @@ -1742,18 +1788,18 @@ const attachProviderGrantToSources = (input: { · 4 unmodified lines | |||
| 1742 | const removeProviderAuthGrantInternal = (input: { | 1788 | const removeProviderAuthGrantInternal = (input: { |
| 1743 | executorState: ExecutorStateStoreShape; | 1789 | executorState: ExecutorStateStoreShape; |
| 1744 | sourceStore: RuntimeSourceStore; | 1790 | sourceStore: RuntimeSourceStore; |
| 1745 | workspaceId: WorkspaceId; | 1791 | scopeId: ScopeId; |
| 1746 | grantId: ProviderAuthGrant["id"]; | 1792 | grantId: ProviderAuthGrant["id"]; |
| 1747 | deleteSecretMaterial: DeleteSecretMaterial; | 1793 | deleteSecretMaterial: DeleteSecretMaterial; |
| 1748 | }): Effect.Effect<boolean, Error, WorkspaceStorageServices> => | 1794 | }): Effect.Effect<boolean, Error, ScopeStorageServices> => |
| 1749 | Effect.gen(function* () { | 1795 | Effect.gen(function* () { |
| 1750 | const grantOption = yield* input.executorState.providerAuthGrants.getById(input.grantId); | 1796 | const grantOption = yield* input.executorState.providerAuthGrants.getById(input.grantId); |
| 1751 | if (Option.isNone(grantOption) || grantOption.value.workspaceId !== input.workspaceId) { | 1797 | if (Option.isNone(grantOption) || grantOption.value.scopeId !== input.scopeId) { |
| 1752 | return false; | 1798 | return false; |
| 1753 | } | 1799 | } |
| 1754 | 1800 | ||
| 1755 | const references = yield* listProviderGrantRefArtifacts(input.executorState, { | 1801 | const references = yield* listProviderGrantRefArtifacts(input.executorState, { |
| 1756 | workspaceId: input.workspaceId, | 1802 | scopeId: input.scopeId, |
| 1757 | grantId: input.grantId, | 1803 | grantId: input.grantId, |
| 1758 | }); | 1804 | }); |
| 1759 | 1805 | ||
| @@ -1762,9 +1808,9 @@ const removeProviderAuthGrantInternal = (input: { · 2 unmodified lines | |||
| 1762 | (artifact) => | 1808 | (artifact) => |
| 1763 | Effect.gen(function* () { | 1809 | Effect.gen(function* () { |
| 1764 | const latestSource = yield* input.sourceStore.loadSourceById({ | 1810 | const latestSource = yield* input.sourceStore.loadSourceById({ |
| 1765 | workspaceId: artifact.workspaceId, | 1811 | scopeId: artifact.scopeId, |
| 1766 | sourceId: artifact.sourceId, | 1812 | sourceId: artifact.sourceId, |
| 1767 | actorAccountId: artifact.actorAccountId, | 1813 | actorScopeId: artifact.actorScopeId, |
| 1768 | }).pipe( | 1814 | }).pipe( |
| 1769 | Effect.catchAll(() => Effect.succeed(null)), | 1815 | Effect.catchAll(() => Effect.succeed(null)), |
| 1770 | ); | 1816 | ); |
| @@ -1773,10 +1819,10 @@ const removeProviderAuthGrantInternal = (input: { · 2 unmodified lines | |||
| 1773 | yield* removeAuthLeaseAndSecrets(input.executorState, { | 1819 | yield* removeAuthLeaseAndSecrets(input.executorState, { |
| 1774 | authArtifactId: artifact.id, | 1820 | authArtifactId: artifact.id, |
| 1775 | }, input.deleteSecretMaterial); | 1821 | }, input.deleteSecretMaterial); |
| 1776 | yield* input.executorState.authArtifacts.removeByWorkspaceSourceAndActor({ | 1822 | yield* input.executorState.authArtifacts.removeByScopeSourceAndActor({ |
| 1777 | workspaceId: artifact.workspaceId, | 1823 | scopeId: artifact.scopeId, |
| 1778 | sourceId: artifact.sourceId, | 1824 | sourceId: artifact.sourceId, |
| 1779 | actorAccountId: artifact.actorAccountId, | 1825 | actorScopeId: artifact.actorScopeId, |
| 1780 | slot: artifact.slot, | 1826 | slot: artifact.slot, |
| 1781 | }); | 1827 | }); |
| 1782 | return; | 1828 | return; |
| @@ -1790,7 +1836,7 @@ const removeProviderAuthGrantInternal = (input: { · 7 unmodified lines | |||
| 1790 | importAuth: artifact.slot === "import" ? { kind: "none" } : latestSource.importAuth, | 1836 | importAuth: artifact.slot === "import" ? { kind: "none" } : latestSource.importAuth, |
| 1791 | updatedAt: Date.now(), | 1837 | updatedAt: Date.now(), |
| 1792 | }, { | 1838 | }, { |
| 1793 | actorAccountId: artifact.actorAccountId, | 1839 | actorScopeId: artifact.actorScopeId, |
| 1794 | }).pipe(Effect.asVoid); | 1840 | }).pipe(Effect.asVoid); |
| 1795 | }), | 1841 | }), |
| 1796 | { discard: true }, | 1842 | { discard: true }, |
| @@ -1809,8 +1855,8 @@ const connectMcpSourceInternal = (input: { · 12 unmodified lines | |||
| 1809 | sourceCatalogSync: RuntimeSourceCatalogSyncShape; | 1855 | sourceCatalogSync: RuntimeSourceCatalogSyncShape; |
| 1810 | getLocalServerBaseUrl?: () => string | undefined; | 1856 | getLocalServerBaseUrl?: () => string | undefined; |
| 1811 | baseUrl?: string | null; | 1857 | baseUrl?: string | null; |
| 1812 | workspaceId: WorkspaceId; | 1858 | scopeId: ScopeId; |
| 1813 | actorAccountId?: AccountId | null; | 1859 | actorScopeId?: ScopeId | null; |
| 1814 | sourceId?: Source["id"] | null; | 1860 | sourceId?: Source["id"] | null; |
| 1815 | executionId?: SourceAuthSession["executionId"]; | 1861 | executionId?: SourceAuthSession["executionId"]; |
| 1816 | interactionId?: SourceAuthSession["interactionId"]; | 1862 | interactionId?: SourceAuthSession["interactionId"]; |
| @@ -1827,7 +1873,7 @@ const connectMcpSourceInternal = (input: { · 10 unmodified lines | |||
| 1827 | cwd?: string | null; | 1873 | cwd?: string | null; |
| 1828 | mcpDiscoveryElicitation?: McpDiscoveryElicitationContext; | 1874 | mcpDiscoveryElicitation?: McpDiscoveryElicitationContext; |
| 1829 | resolveSecretMaterial: ResolveSecretMaterial; | 1875 | resolveSecretMaterial: ResolveSecretMaterial; |
| 1830 | }): Effect.Effect<McpSourceConnectResult, Error, WorkspaceStorageServices> => | 1876 | }): Effect.Effect<McpSourceConnectResult, Error, ScopeStorageServices> => |
| 1831 | Effect.gen(function* () { | 1877 | Effect.gen(function* () { |
| 1832 | const lookupEndpoint = input.sourceId | 1878 | const lookupEndpoint = input.sourceId |
| 1833 | ? null | 1879 | ? null |
| @@ -1840,9 +1886,9 @@ const connectMcpSourceInternal = (input: { · 6 unmodified lines | |||
| 1840 | const existing = yield* ( | 1886 | const existing = yield* ( |
| 1841 | input.sourceId | 1887 | input.sourceId |
| 1842 | ? input.sourceStore.loadSourceById({ | 1888 | ? input.sourceStore.loadSourceById({ |
| 1843 | workspaceId: input.workspaceId, | 1889 | scopeId: input.scopeId, |
| 1844 | sourceId: input.sourceId, | 1890 | sourceId: input.sourceId, |
| 1845 | actorAccountId: input.actorAccountId, | 1891 | actorScopeId: input.actorScopeId, |
| 1846 | }).pipe( | 1892 | }).pipe( |
| 1847 | Effect.flatMap((source) => | 1893 | Effect.flatMap((source) => |
| 1848 | sourceAdapterRequiresInteractiveConnect(source.kind) | 1894 | sourceAdapterRequiresInteractiveConnect(source.kind) |
| @@ -1850,8 +1896,8 @@ const connectMcpSourceInternal = (input: { · 1 unmodified line | |||
| 1850 | : Effect.fail(runtimeEffectError("sources/source-auth-service", `Expected MCP source, received ${source.kind}`)), | 1896 | : Effect.fail(runtimeEffectError("sources/source-auth-service", `Expected MCP source, received ${source.kind}`)), |
| 1851 | ), | 1897 | ), |
| 1852 | ) | 1898 | ) |
| 1853 | : input.sourceStore.loadSourcesInWorkspace(input.workspaceId, { | 1899 | : input.sourceStore.loadSourcesInScope(input.scopeId, { |
| 1854 | actorAccountId: input.actorAccountId, | 1900 | actorScopeId: input.actorScopeId, |
| 1855 | }).pipe( | 1901 | }).pipe( |
| 1856 | Effect.map((sources) => | 1902 | Effect.map((sources) => |
| 1857 | sources.find( | 1903 | sources.find( |
| @@ -1943,7 +1989,7 @@ const connectMcpSourceInternal = (input: { · 85 unmodified lines | |||
| 1943 | now, | 1989 | now, |
| 1944 | }) | 1990 | }) |
| 1945 | : yield* createSourceFromPayload({ | 1991 | : yield* createSourceFromPayload({ |
| 1946 | workspaceId: input.workspaceId, | 1992 | scopeId: input.scopeId, |
| 1947 | sourceId: SourceIdSchema.make(`src_${crypto.randomUUID()}`), | 1993 | sourceId: SourceIdSchema.make(`src_${crypto.randomUUID()}`), |
| 1948 | payload: { | 1994 | payload: { |
| 1949 | name: chosenName, | 1995 | name: chosenName, |
| @@ -1969,11 +2015,11 @@ const connectMcpSourceInternal = (input: { · 19 unmodified lines | |||
| 1969 | }); | 2015 | }); |
| 1970 | 2016 | ||
| 1971 | const persistedDraft = yield* input.sourceStore.persistSource(draftSource, { | 2017 | const persistedDraft = yield* input.sourceStore.persistSource(draftSource, { |
| 1972 | actorAccountId: input.actorAccountId, | 2018 | actorScopeId: input.actorScopeId, |
| 1973 | }); | 2019 | }); |
| 1974 | yield* input.sourceCatalogSync.sync({ | 2020 | yield* input.sourceCatalogSync.sync({ |
| 1975 | source: persistedDraft, | 2021 | source: persistedDraft, |
| 1976 | actorAccountId: input.actorAccountId, | 2022 | actorScopeId: input.actorScopeId, |
| 1977 | }); | 2023 | }); |
| 1978 | 2024 | ||
| 1979 | const discovered = yield* Effect.either( | 2025 | const discovered = yield* Effect.either( |
| @@ -1988,7 +2034,7 @@ const connectMcpSourceInternal = (input: { · 8 unmodified lines | |||
| 1988 | onRight: (result) => | 2034 | onRight: (result) => |
| 1989 | Effect.gen(function* () { | 2035 | Effect.gen(function* () { |
| 1990 | const connected = yield* updateSourceStatus(input.sourceStore, persistedDraft, { | 2036 | const connected = yield* updateSourceStatus(input.sourceStore, persistedDraft, { |
| 1991 | actorAccountId: input.actorAccountId, | 2037 | actorScopeId: input.actorScopeId, |
| 1992 | status: "connected", | 2038 | status: "connected", |
| 1993 | lastError: null, | 2039 | lastError: null, |
| 1994 | auth: { kind: "none" }, | 2040 | auth: { kind: "none" }, |
| @@ -2003,7 +2049,7 @@ const connectMcpSourceInternal = (input: { · 8 unmodified lines | |||
| 2003 | return yield* Either.match(indexed, { | 2049 | return yield* Either.match(indexed, { |
| 2004 | onLeft: (error) => | 2050 | onLeft: (error) => |
| 2005 | updateSourceStatus(input.sourceStore, connected, { | 2051 | updateSourceStatus(input.sourceStore, connected, { |
| 2006 | actorAccountId: input.actorAccountId, | 2052 | actorScopeId: input.actorScopeId, |
| 2007 | status: "error", | 2053 | status: "error", |
| 2008 | lastError: error.message, | 2054 | lastError: error.message, |
| 2009 | }).pipe( | 2055 | }).pipe( |
| @@ -2031,7 +2077,7 @@ const connectMcpSourceInternal = (input: { · 21 unmodified lines | |||
| 2031 | const state = crypto.randomUUID(); | 2077 | const state = crypto.randomUUID(); |
| 2032 | const redirectUrl = resolveSourceCredentialOauthCompleteUrl({ | 2078 | const redirectUrl = resolveSourceCredentialOauthCompleteUrl({ |
| 2033 | baseUrl: localServerBaseUrl, | 2079 | baseUrl: localServerBaseUrl, |
| 2034 | workspaceId: input.workspaceId, | 2080 | scopeId: input.scopeId, |
| 2035 | sourceId: persistedDraft.id, | 2081 | sourceId: persistedDraft.id, |
| 2036 | }); | 2082 | }); |
| 2037 | const oauthStart = yield* startMcpOAuthAuthorization({ | 2083 | const oauthStart = yield* startMcpOAuthAuthorization({ |
| @@ -2041,7 +2087,7 @@ const connectMcpSourceInternal = (input: { · 3 unmodified lines | |||
| 2041 | }); | 2087 | }); |
| 2042 | 2088 | ||
| 2043 | const authRequiredSource = yield* updateSourceStatus(input.sourceStore, persistedDraft, { | 2089 | const authRequiredSource = yield* updateSourceStatus(input.sourceStore, persistedDraft, { |
| 2044 | actorAccountId: input.actorAccountId, | 2090 | actorScopeId: input.actorScopeId, |
| 2045 | status: "auth_required", | 2091 | status: "auth_required", |
| 2046 | lastError: null, | 2092 | lastError: null, |
| 2047 | }); | 2093 | }); |
| @@ -2049,9 +2095,9 @@ const connectMcpSourceInternal = (input: { · 1 unmodified line | |||
| 2049 | const sessionNow = Date.now(); | 2095 | const sessionNow = Date.now(); |
| 2050 | yield* input.executorState.sourceAuthSessions.upsert({ | 2096 | yield* input.executorState.sourceAuthSessions.upsert({ |
| 2051 | id: sessionId, | 2097 | id: sessionId, |
| 2052 | workspaceId: input.workspaceId, | 2098 | scopeId: input.scopeId, |
| 2053 | sourceId: authRequiredSource.id, | 2099 | sourceId: authRequiredSource.id, |
| 2054 | actorAccountId: input.actorAccountId ?? null, | 2100 | actorScopeId: input.actorScopeId ?? null, |
| 2055 | credentialSlot: "runtime", | 2101 | credentialSlot: "runtime", |
| 2056 | executionId: input.executionId ?? null, | 2102 | executionId: input.executionId ?? null, |
| 2057 | interactionId: input.interactionId ?? null, | 2103 | interactionId: input.interactionId ?? null, |
| @@ -2095,16 +2141,17 @@ const addExecutorHttpSource = (input: { · 37 unmodified lines | |||
| 2095 | resolveSecretMaterial: ResolveSecretMaterial; | 2141 | resolveSecretMaterial: ResolveSecretMaterial; |
| 2096 | getLocalServerBaseUrl?: () => string | undefined; | 2142 | getLocalServerBaseUrl?: () => string | undefined; |
| 2097 | baseUrl?: string | null; | 2143 | baseUrl?: string | null; |
| 2098 | }): Effect.Effect<ExecutorSourceAddResult, Error, WorkspaceStorageServices> => | 2144 | localScopeState?: RuntimeLocalScopeState; |
| 2145 | }): Effect.Effect<ExecutorSourceAddResult, Error, ScopeStorageServices> => | ||
| 2099 | Effect.gen(function* () { | 2146 | Effect.gen(function* () { |
| 2100 | const normalizedEndpoint = normalizeEndpoint(input.sourceInput.endpoint); | 2147 | const normalizedEndpoint = normalizeEndpoint(input.sourceInput.endpoint); |
| 2101 | const normalizedSpecUrl = input.sourceInput.kind === "openapi" | 2148 | const normalizedSpecUrl = input.sourceInput.kind === "openapi" |
| 2102 | ? normalizeEndpoint(input.sourceInput.specUrl) | 2149 | ? normalizeEndpoint(input.sourceInput.specUrl) |
| 2103 | : null; | 2150 | : null; |
| 2104 | const existingSources = yield* input.sourceStore.loadSourcesInWorkspace( | 2151 | const existingSources = yield* input.sourceStore.loadSourcesInScope( |
| 2105 | input.sourceInput.workspaceId, | 2152 | input.sourceInput.scopeId, |
| 2106 | { | 2153 | { |
| 2107 | actorAccountId: input.sourceInput.actorAccountId, | 2154 | actorScopeId: input.sourceInput.actorScopeId, |
| 2108 | }, | 2155 | }, |
| 2109 | ); | 2156 | ); |
| 2110 | const existing = existingSources.find((source) => { | 2157 | const existing = existingSources.find((source) => { |
| @@ -2175,7 +2222,7 @@ const addExecutorHttpSource = (input: { · 64 unmodified lines | |||
| 2175 | now, | 2222 | now, |
| 2176 | }) | 2223 | }) |
| 2177 | : yield* createSourceFromPayload({ | 2224 | : yield* createSourceFromPayload({ |
| 2178 | workspaceId: input.sourceInput.workspaceId, | 2225 | scopeId: input.sourceInput.scopeId, |
| 2179 | sourceId: SourceIdSchema.make(`src_${crypto.randomUUID()}`), | 2226 | sourceId: SourceIdSchema.make(`src_${crypto.randomUUID()}`), |
| 2180 | payload: { | 2227 | payload: { |
| 2181 | name: chosenName, | 2228 | name: chosenName, |
| @@ -2200,7 +2247,7 @@ const addExecutorHttpSource = (input: { · 18 unmodified lines | |||
| 2200 | }); | 2247 | }); |
| 2201 | 2248 | ||
| 2202 | const persistedDraft = yield* input.sourceStore.persistSource(draftSource, { | 2249 | const persistedDraft = yield* input.sourceStore.persistSource(draftSource, { |
| 2203 | actorAccountId: input.sourceInput.actorAccountId, | 2250 | actorScopeId: input.sourceInput.actorScopeId, |
| 2204 | }); | 2251 | }); |
| 2205 | 2252 | ||
| 2206 | if (shouldPromptForExecutorHttpRuntimeCredentialSetup({ | 2253 | if (shouldPromptForExecutorHttpRuntimeCredentialSetup({ |
| @@ -2215,7 +2262,7 @@ const addExecutorHttpSource = (input: { · 8 unmodified lines | |||
| 2215 | executorState: input.executorState, | 2262 | executorState: input.executorState, |
| 2216 | sourceStore: input.sourceStore, | 2263 | sourceStore: input.sourceStore, |
| 2217 | source: persistedDraft, | 2264 | source: persistedDraft, |
| 2218 | actorAccountId: input.sourceInput.actorAccountId, | 2265 | actorScopeId: input.sourceInput.actorScopeId, |
| 2219 | executionId: input.sourceInput.executionId, | 2266 | executionId: input.sourceInput.executionId, |
| 2220 | interactionId: input.sourceInput.interactionId, | 2267 | interactionId: input.sourceInput.interactionId, |
| 2221 | baseUrl, | 2268 | baseUrl, |
| @@ -2228,7 +2275,7 @@ const addExecutorHttpSource = (input: { · 6 unmodified lines | |||
| 2228 | } | 2275 | } |
| 2229 | 2276 | ||
| 2230 | const authRequiredSource = yield* updateSourceStatus(input.sourceStore, persistedDraft, { | 2277 | const authRequiredSource = yield* updateSourceStatus(input.sourceStore, persistedDraft, { |
| 2231 | actorAccountId: input.sourceInput.actorAccountId, | 2278 | actorScopeId: input.sourceInput.actorScopeId, |
| 2232 | status: "auth_required", | 2279 | status: "auth_required", |
| 2233 | lastError: null, | 2280 | lastError: null, |
| 2234 | }); | 2281 | }); |
| @@ -2246,7 +2293,7 @@ const addExecutorHttpSource = (input: { · 11 unmodified lines | |||
| 2246 | ...persistedDraft, | 2293 | ...persistedDraft, |
| 2247 | status: "connected", | 2294 | status: "connected", |
| 2248 | }, | 2295 | }, |
| 2249 | actorAccountId: input.sourceInput.actorAccountId, | 2296 | actorScopeId: input.sourceInput.actorScopeId, |
| 2250 | }), | 2297 | }), |
| 2251 | ); | 2298 | ); |
| 2252 | 2299 | ||
| @@ -2254,7 +2301,7 @@ const addExecutorHttpSource = (input: { · 1 unmodified line | |||
| 2254 | onLeft: (error) => | 2301 | onLeft: (error) => |
| 2255 | isSourceCredentialRequiredError(error) | 2302 | isSourceCredentialRequiredError(error) |
| 2256 | ? updateSourceStatus(input.sourceStore, persistedDraft, { | 2303 | ? updateSourceStatus(input.sourceStore, persistedDraft, { |
| 2257 | actorAccountId: input.sourceInput.actorAccountId, | 2304 | actorScopeId: input.sourceInput.actorScopeId, |
| 2258 | status: "auth_required", | 2305 | status: "auth_required", |
| 2259 | lastError: null, | 2306 | lastError: null, |
| 2260 | }).pipe( | 2307 | }).pipe( |
| @@ -2267,7 +2314,7 @@ const addExecutorHttpSource = (input: { · 6 unmodified lines | |||
| 2267 | ), | 2314 | ), |
| 2268 | ) | 2315 | ) |
| 2269 | : updateSourceStatus(input.sourceStore, persistedDraft, { | 2316 | : updateSourceStatus(input.sourceStore, persistedDraft, { |
| 2270 | actorAccountId: input.sourceInput.actorAccountId, | 2317 | actorScopeId: input.sourceInput.actorScopeId, |
| 2271 | status: "error", | 2318 | status: "error", |
| 2272 | lastError: error.message, | 2319 | lastError: error.message, |
| 2273 | }).pipe( | 2320 | }).pipe( |
| @@ -2275,7 +2322,7 @@ const addExecutorHttpSource = (input: { · 1 unmodified line | |||
| 2275 | ), | 2322 | ), |
| 2276 | onRight: () => | 2323 | onRight: () => |
| 2277 | updateSourceStatus(input.sourceStore, persistedDraft, { | 2324 | updateSourceStatus(input.sourceStore, persistedDraft, { |
| 2278 | actorAccountId: input.sourceInput.actorAccountId, | 2325 | actorScopeId: input.sourceInput.actorScopeId, |
| 2279 | status: "connected", | 2326 | status: "connected", |
| 2280 | lastError: null, | 2327 | lastError: null, |
| 2281 | }).pipe( | 2328 | }).pipe( |
| @@ -2308,7 +2355,8 @@ const addExecutorGoogleDiscoverySource = (input: { · 26 unmodified lines | |||
| 2308 | resolveSecretMaterial: ResolveSecretMaterial; | 2355 | resolveSecretMaterial: ResolveSecretMaterial; |
| 2309 | getLocalServerBaseUrl?: () => string | undefined; | 2356 | getLocalServerBaseUrl?: () => string | undefined; |
| 2310 | baseUrl?: string | null; | 2357 | baseUrl?: string | null; |
| 2311 | }): Effect.Effect<ExecutorSourceAddResult, Error, WorkspaceStorageServices> => | 2358 | localScopeState?: RuntimeLocalScopeState; |
| 2359 | }): Effect.Effect<ExecutorSourceAddResult, Error, ScopeStorageServices> => | ||
| 2312 | Effect.gen(function* () { | 2360 | Effect.gen(function* () { |
| 2313 | const normalizedService = input.sourceInput.service.trim(); | 2361 | const normalizedService = input.sourceInput.service.trim(); |
| 2314 | const normalizedVersion = input.sourceInput.version.trim(); | 2362 | const normalizedVersion = input.sourceInput.version.trim(); |
| @@ -2316,10 +2364,10 @@ const addExecutorGoogleDiscoverySource = (input: { · 1 unmodified line | |||
| 2316 | trimOrNull(input.sourceInput.discoveryUrl) | 2364 | trimOrNull(input.sourceInput.discoveryUrl) |
| 2317 | ?? defaultGoogleDiscoveryUrl(normalizedService, normalizedVersion), | 2365 | ?? defaultGoogleDiscoveryUrl(normalizedService, normalizedVersion), |
| 2318 | ); | 2366 | ); |
| 2319 | const existingSources = yield* input.sourceStore.loadSourcesInWorkspace( | 2367 | const existingSources = yield* input.sourceStore.loadSourcesInScope( |
| 2320 | input.sourceInput.workspaceId, | 2368 | input.sourceInput.scopeId, |
| 2321 | { | 2369 | { |
| 2322 | actorAccountId: input.sourceInput.actorAccountId, | 2370 | actorScopeId: input.sourceInput.actorScopeId, |
| 2323 | }, | 2371 | }, |
| 2324 | ); | 2372 | ); |
| 2325 | const existing = existingSources.find((source) => { | 2373 | const existing = existingSources.find((source) => { |
| @@ -2397,7 +2445,7 @@ const addExecutorGoogleDiscoverySource = (input: { · 71 unmodified lines | |||
| 2397 | now, | 2445 | now, |
| 2398 | }) | 2446 | }) |
| 2399 | : yield* createSourceFromPayload({ | 2447 | : yield* createSourceFromPayload({ |
| 2400 | workspaceId: input.sourceInput.workspaceId, | 2448 | scopeId: input.sourceInput.scopeId, |
| 2401 | sourceId: SourceIdSchema.make(`src_${crypto.randomUUID()}`), | 2449 | sourceId: SourceIdSchema.make(`src_${crypto.randomUUID()}`), |
| 2402 | payload: { | 2450 | payload: { |
| 2403 | name: chosenName, | 2451 | name: chosenName, |
| @@ -2421,7 +2469,7 @@ const addExecutorGoogleDiscoverySource = (input: { · 17 unmodified lines | |||
| 2421 | }); | 2469 | }); |
| 2422 | 2470 | ||
| 2423 | const persistedDraft = yield* input.sourceStore.persistSource(draftSource, { | 2471 | const persistedDraft = yield* input.sourceStore.persistSource(draftSource, { |
| 2424 | actorAccountId: input.sourceInput.actorAccountId, | 2472 | actorScopeId: input.sourceInput.actorScopeId, |
| 2425 | }); | 2473 | }); |
| 2426 | const googleAdapter = getSourceAdapterForSource(persistedDraft); | 2474 | const googleAdapter = getSourceAdapterForSource(persistedDraft); |
| 2427 | const providerAuthTarget = yield* resolveRuntimeProviderAuthTarget(persistedDraft); | 2475 | const providerAuthTarget = yield* resolveRuntimeProviderAuthTarget(persistedDraft); |
| @@ -2431,18 +2479,19 @@ const addExecutorGoogleDiscoverySource = (input: { · 3 unmodified lines | |||
| 2431 | && input.sourceInput.auth === undefined | 2479 | && input.sourceInput.auth === undefined |
| 2432 | && persistedDraft.auth.kind === "none" | 2480 | && persistedDraft.auth.kind === "none" |
| 2433 | ) { | 2481 | ) { |
| 2434 | let workspaceOauthClient: ResolvedWorkspaceOauthClient | null = null; | 2482 | let scopeOauthClient: ResolvedScopeOauthClient | null = null; |
| 2435 | if (input.sourceInput.workspaceOauthClientId) { | 2483 | if (input.sourceInput.scopeOauthClientId) { |
| 2436 | workspaceOauthClient = yield* resolveWorkspaceOauthClientById({ | 2484 | scopeOauthClient = yield* resolveScopeOauthClientById({ |
| 2437 | executorState: input.executorState, | 2485 | executorState: input.executorState, |
| 2438 | workspaceId: persistedDraft.workspaceId, | 2486 | scopeId: persistedDraft.scopeId, |
| 2439 | oauthClientId: input.sourceInput.workspaceOauthClientId, | 2487 | oauthClientId: input.sourceInput.scopeOauthClientId, |
| 2440 | providerKey: providerAuthTarget.setupConfig.providerKey, | 2488 | providerKey: providerAuthTarget.setupConfig.providerKey, |
| 2489 | localScopeState: input.localScopeState, | ||
| 2441 | }); | 2490 | }); |
| 2442 | } else if (input.sourceInput.oauthClient) { | 2491 | } else if (input.sourceInput.oauthClient) { |
| 2443 | workspaceOauthClient = yield* createWorkspaceOauthClient({ | 2492 | scopeOauthClient = yield* createScopeOauthClient({ |
| 2444 | executorState: input.executorState, | 2493 | executorState: input.executorState, |
| 2445 | workspaceId: persistedDraft.workspaceId, | 2494 | scopeId: persistedDraft.scopeId, |
| 2446 | providerKey: providerAuthTarget.setupConfig.providerKey, | 2495 | providerKey: providerAuthTarget.setupConfig.providerKey, |
| 2447 | oauthClient: input.sourceInput.oauthClient, | 2496 | oauthClient: input.sourceInput.oauthClient, |
| 2448 | label: `${chosenName} OAuth Client`, | 2497 | label: `${chosenName} OAuth Client`, |
| @@ -2451,7 +2500,7 @@ const addExecutorGoogleDiscoverySource = (input: { · 2 unmodified lines | |||
| 2451 | }); | 2500 | }); |
| 2452 | } | 2501 | } |
| 2453 | 2502 | ||
| 2454 | if (workspaceOauthClient === null) { | 2503 | if (scopeOauthClient === null) { |
| 2455 | return yield* runtimeEffectError( | 2504 | return yield* runtimeEffectError( |
| 2456 | "sources/source-auth-service", | 2505 | "sources/source-auth-service", |
| 2457 | `${providerAuthTarget.setupConfig.providerKey} shared auth requires a workspace OAuth client`, | 2506 | `${providerAuthTarget.setupConfig.providerKey} shared auth requires a workspace OAuth client`, |
| @@ -2462,14 +2511,15 @@ const addExecutorGoogleDiscoverySource = (input: { · 4 unmodified lines | |||
| 2462 | executorState: input.executorState, | 2511 | executorState: input.executorState, |
| 2463 | sourceStore: input.sourceStore, | 2512 | sourceStore: input.sourceStore, |
| 2464 | sourceCatalogSync: input.sourceCatalogSync, | 2513 | sourceCatalogSync: input.sourceCatalogSync, |
| 2465 | workspaceId: persistedDraft.workspaceId, | 2514 | scopeId: persistedDraft.scopeId, |
| 2466 | actorAccountId: input.sourceInput.actorAccountId, | 2515 | actorScopeId: input.sourceInput.actorScopeId, |
| 2467 | executionId: input.sourceInput.executionId, | 2516 | executionId: input.sourceInput.executionId, |
| 2468 | interactionId: input.sourceInput.interactionId, | 2517 | interactionId: input.sourceInput.interactionId, |
| 2469 | baseUrl: input.baseUrl, | 2518 | baseUrl: input.baseUrl, |
| 2470 | getLocalServerBaseUrl: input.getLocalServerBaseUrl, | 2519 | getLocalServerBaseUrl: input.getLocalServerBaseUrl, |
| 2471 | workspaceOauthClient, | 2520 | scopeOauthClient, |
| 2472 | targets: [providerAuthTarget], | 2521 | targets: [providerAuthTarget], |
| 2522 | localScopeState: input.localScopeState, | ||
| 2473 | }); | 2523 | }); |
| 2474 | 2524 | ||
| 2475 | return providerAuthResult.kind === "connected" | 2525 | return providerAuthResult.kind === "connected" |
| @@ -2507,7 +2557,7 @@ const addExecutorGoogleDiscoverySource = (input: { · 31 unmodified lines | |||
| 2507 | executorState: input.executorState, | 2557 | executorState: input.executorState, |
| 2508 | sourceStore: input.sourceStore, | 2558 | sourceStore: input.sourceStore, |
| 2509 | source: persistedDraft, | 2559 | source: persistedDraft, |
| 2510 | actorAccountId: input.sourceInput.actorAccountId, | 2560 | actorScopeId: input.sourceInput.actorScopeId, |
| 2511 | executionId: input.sourceInput.executionId, | 2561 | executionId: input.sourceInput.executionId, |
| 2512 | interactionId: input.sourceInput.interactionId, | 2562 | interactionId: input.sourceInput.interactionId, |
| 2513 | baseUrl, | 2563 | baseUrl, |
| @@ -2520,7 +2570,7 @@ const addExecutorGoogleDiscoverySource = (input: { · 6 unmodified lines | |||
| 2520 | } | 2570 | } |
| 2521 | 2571 | ||
| 2522 | const authRequiredSource = yield* updateSourceStatus(input.sourceStore, persistedDraft, { | 2572 | const authRequiredSource = yield* updateSourceStatus(input.sourceStore, persistedDraft, { |
| 2523 | actorAccountId: input.sourceInput.actorAccountId, | 2573 | actorScopeId: input.sourceInput.actorScopeId, |
| 2524 | status: "auth_required", | 2574 | status: "auth_required", |
| 2525 | lastError: null, | 2575 | lastError: null, |
| 2526 | }); | 2576 | }); |
| @@ -2538,7 +2588,7 @@ const addExecutorGoogleDiscoverySource = (input: { · 11 unmodified lines | |||
| 2538 | ...persistedDraft, | 2588 | ...persistedDraft, |
| 2539 | status: "connected", | 2589 | status: "connected", |
| 2540 | }, | 2590 | }, |
| 2541 | actorAccountId: input.sourceInput.actorAccountId, | 2591 | actorScopeId: input.sourceInput.actorScopeId, |
| 2542 | }), | 2592 | }), |
| 2543 | ); | 2593 | ); |
| 2544 | 2594 | ||
| @@ -2546,7 +2596,7 @@ const addExecutorGoogleDiscoverySource = (input: { · 1 unmodified line | |||
| 2546 | onLeft: (error) => | 2596 | onLeft: (error) => |
| 2547 | isSourceCredentialRequiredError(error) | 2597 | isSourceCredentialRequiredError(error) |
| 2548 | ? updateSourceStatus(input.sourceStore, persistedDraft, { | 2598 | ? updateSourceStatus(input.sourceStore, persistedDraft, { |
| 2549 | actorAccountId: input.sourceInput.actorAccountId, | 2599 | actorScopeId: input.sourceInput.actorScopeId, |
| 2550 | status: "auth_required", | 2600 | status: "auth_required", |
| 2551 | lastError: null, | 2601 | lastError: null, |
| 2552 | }).pipe( | 2602 | }).pipe( |
| @@ -2559,7 +2609,7 @@ const addExecutorGoogleDiscoverySource = (input: { · 6 unmodified lines | |||
| 2559 | ), | 2609 | ), |
| 2560 | ) | 2610 | ) |
| 2561 | : updateSourceStatus(input.sourceStore, persistedDraft, { | 2611 | : updateSourceStatus(input.sourceStore, persistedDraft, { |
| 2562 | actorAccountId: input.sourceInput.actorAccountId, | 2612 | actorScopeId: input.sourceInput.actorScopeId, |
| 2563 | status: "error", | 2613 | status: "error", |
| 2564 | lastError: error.message, | 2614 | lastError: error.message, |
| 2565 | }).pipe( | 2615 | }).pipe( |
| @@ -2567,7 +2617,7 @@ const addExecutorGoogleDiscoverySource = (input: { · 1 unmodified line | |||
| 2567 | ), | 2617 | ), |
| 2568 | onRight: () => | 2618 | onRight: () => |
| 2569 | updateSourceStatus(input.sourceStore, persistedDraft, { | 2619 | updateSourceStatus(input.sourceStore, persistedDraft, { |
| 2570 | actorAccountId: input.sourceInput.actorAccountId, | 2620 | actorScopeId: input.sourceInput.actorScopeId, |
| 2571 | status: "connected", | 2621 | status: "connected", |
| 2572 | lastError: null, | 2622 | lastError: null, |
| 2573 | }).pipe( | 2623 | }).pipe( |
| @@ -2587,16 +2637,17 @@ const connectGoogleDiscoveryBatchInternal = (input: { · 13 unmodified lines | |||
| 2587 | sourceCatalogSync: RuntimeSourceCatalogSyncShape; | 2637 | sourceCatalogSync: RuntimeSourceCatalogSyncShape; |
| 2588 | sourceInput: ConnectGoogleDiscoveryBatchInput; | 2638 | sourceInput: ConnectGoogleDiscoveryBatchInput; |
| 2589 | getLocalServerBaseUrl?: () => string | undefined; | 2639 | getLocalServerBaseUrl?: () => string | undefined; |
| 2590 | }): Effect.Effect<ConnectGoogleDiscoveryBatchResult, Error, WorkspaceStorageServices> => | 2640 | localScopeState?: RuntimeLocalScopeState; |
| 2641 | }): Effect.Effect<ConnectGoogleDiscoveryBatchResult, Error, ScopeStorageServices> => | ||
| 2591 | Effect.gen(function* () { | 2642 | Effect.gen(function* () { |
| 2592 | if (input.sourceInput.sources.length === 0) { | 2643 | if (input.sourceInput.sources.length === 0) { |
| 2593 | return yield* runtimeEffectError("sources/source-auth-service", "Google batch connect requires at least one source"); | 2644 | return yield* runtimeEffectError("sources/source-auth-service", "Google batch connect requires at least one source"); |
| 2594 | } | 2645 | } |
| 2595 | 2646 | ||
| 2596 | const existingSources = yield* input.sourceStore.loadSourcesInWorkspace( | 2647 | const existingSources = yield* input.sourceStore.loadSourcesInScope( |
| 2597 | input.sourceInput.workspaceId, | 2648 | input.sourceInput.scopeId, |
| 2598 | { | 2649 | { |
| 2599 | actorAccountId: input.sourceInput.actorAccountId, | 2650 | actorScopeId: input.sourceInput.actorScopeId, |
| 2600 | }, | 2651 | }, |
| 2601 | ); | 2652 | ); |
| 2602 | 2653 | ||
| @@ -2664,7 +2715,7 @@ const connectGoogleDiscoveryBatchInternal = (input: { · 61 unmodified lines | |||
| 2664 | now, | 2715 | now, |
| 2665 | }) | 2716 | }) |
| 2666 | : yield* createSourceFromPayload({ | 2717 | : yield* createSourceFromPayload({ |
| 2667 | workspaceId: input.sourceInput.workspaceId, | 2718 | scopeId: input.sourceInput.scopeId, |
| 2668 | sourceId: SourceIdSchema.make(`src_${crypto.randomUUID()}`), | 2719 | sourceId: SourceIdSchema.make(`src_${crypto.randomUUID()}`), |
| 2669 | payload: { | 2720 | payload: { |
| 2670 | name: chosenName, | 2721 | name: chosenName, |
| @@ -2688,7 +2739,7 @@ const connectGoogleDiscoveryBatchInternal = (input: { · 17 unmodified lines | |||
| 2688 | }); | 2739 | }); |
| 2689 | 2740 | ||
| 2690 | const persistedDraft = yield* input.sourceStore.persistSource(draftSource, { | 2741 | const persistedDraft = yield* input.sourceStore.persistSource(draftSource, { |
| 2691 | actorAccountId: input.sourceInput.actorAccountId, | 2742 | actorScopeId: input.sourceInput.actorScopeId, |
| 2692 | }); | 2743 | }); |
| 2693 | const providerAuthTarget = yield* resolveRuntimeProviderAuthTarget(persistedDraft); | 2744 | const providerAuthTarget = yield* resolveRuntimeProviderAuthTarget(persistedDraft); |
| 2694 | if (providerAuthTarget === null) { | 2745 | if (providerAuthTarget === null) { |
| @@ -2700,28 +2751,30 @@ const connectGoogleDiscoveryBatchInternal = (input: { · 5 unmodified lines | |||
| 2700 | { discard: false }, | 2751 | { discard: false }, |
| 2701 | ); | 2752 | ); |
| 2702 | 2753 | ||
| 2703 | const workspaceOauthClient = yield* resolveWorkspaceOauthClientById({ | 2754 | const scopeOauthClient = yield* resolveScopeOauthClientById({ |
| 2704 | executorState: input.executorState, | 2755 | executorState: input.executorState, |
| 2705 | workspaceId: input.sourceInput.workspaceId, | 2756 | scopeId: input.sourceInput.scopeId, |
| 2706 | oauthClientId: input.sourceInput.workspaceOauthClientId, | 2757 | oauthClientId: input.sourceInput.scopeOauthClientId, |
| 2707 | providerKey: persistedTargets[0]!.setupConfig.providerKey, | 2758 | providerKey: persistedTargets[0]!.setupConfig.providerKey, |
| 2759 | localScopeState: input.localScopeState, | ||
| 2708 | }); | 2760 | }); |
| 2709 | if (workspaceOauthClient === null) { | 2761 | if (scopeOauthClient === null) { |
| 2710 | return yield* runtimeEffectError("sources/source-auth-service", `Workspace OAuth client not found: ${input.sourceInput.workspaceOauthClientId}`); | 2762 | return yield* runtimeEffectError("sources/source-auth-service", `Scope OAuth client not found: ${input.sourceInput.scopeOauthClientId}`); |
| 2711 | } | 2763 | } |
| 2712 | 2764 | ||
| 2713 | const providerAuthResult = yield* connectSourcesWithProviderRuntimeAuth({ | 2765 | const providerAuthResult = yield* connectSourcesWithProviderRuntimeAuth({ |
| 2714 | executorState: input.executorState, | 2766 | executorState: input.executorState, |
| 2715 | sourceStore: input.sourceStore, | 2767 | sourceStore: input.sourceStore, |
| 2716 | sourceCatalogSync: input.sourceCatalogSync, | 2768 | sourceCatalogSync: input.sourceCatalogSync, |
| 2717 | workspaceId: input.sourceInput.workspaceId, | 2769 | scopeId: input.sourceInput.scopeId, |
| 2718 | actorAccountId: input.sourceInput.actorAccountId, | 2770 | actorScopeId: input.sourceInput.actorScopeId, |
| 2719 | executionId: input.sourceInput.executionId, | 2771 | executionId: input.sourceInput.executionId, |
| 2720 | interactionId: input.sourceInput.interactionId, | 2772 | interactionId: input.sourceInput.interactionId, |
| 2721 | baseUrl: input.sourceInput.baseUrl, | 2773 | baseUrl: input.sourceInput.baseUrl, |
| 2722 | getLocalServerBaseUrl: input.getLocalServerBaseUrl, | 2774 | getLocalServerBaseUrl: input.getLocalServerBaseUrl, |
| 2723 | workspaceOauthClient, | 2775 | scopeOauthClient, |
| 2724 | targets: persistedTargets, | 2776 | targets: persistedTargets, |
| 2777 | localScopeState: input.localScopeState, | ||
| 2725 | }); | 2778 | }); |
| 2726 | 2779 | ||
| 2727 | if (providerAuthResult.kind === "connected") { | 2780 | if (providerAuthResult.kind === "connected") { |
| @@ -2749,10 +2802,10 @@ const connectGoogleDiscoveryBatchInternal = (input: { · 21 unmodified lines | |||
| 2749 | 2802 | ||
| 2750 | type RuntimeSourceAuthServiceShape = { | 2803 | type RuntimeSourceAuthServiceShape = { |
| 2751 | getSourceById: (input: { | 2804 | getSourceById: (input: { |
| 2752 | workspaceId: WorkspaceId; | 2805 | scopeId: ScopeId; |
| 2753 | sourceId: Source["id"]; | 2806 | sourceId: Source["id"]; |
| 2754 | actorAccountId?: AccountId | null; | 2807 | actorScopeId?: ScopeId | null; |
| 2755 | }) => Effect.Effect<Source, Error, WorkspaceStorageServices>; | 2808 | }) => Effect.Effect<Source, Error, ScopeStorageServices>; |
| 2756 | getLocalServerBaseUrl: () => string | null; | 2809 | getLocalServerBaseUrl: () => string | null; |
| 2757 | storeSecretMaterial: (input: { | 2810 | storeSecretMaterial: (input: { |
| 2758 | purpose: SecretMaterialPurpose; | 2811 | purpose: SecretMaterialPurpose; |
| @@ -2764,28 +2817,28 @@ type RuntimeSourceAuthServiceShape = { · 5 unmodified lines | |||
| 2764 | mcpDiscoveryElicitation?: McpDiscoveryElicitationContext; | 2817 | mcpDiscoveryElicitation?: McpDiscoveryElicitationContext; |
| 2765 | baseUrl?: string | null; | 2818 | baseUrl?: string | null; |
| 2766 | }, | 2819 | }, |
| 2767 | ) => Effect.Effect<ExecutorSourceAddResult, Error, WorkspaceStorageServices>; | 2820 | ) => Effect.Effect<ExecutorSourceAddResult, Error, ScopeStorageServices>; |
| 2768 | connectGoogleDiscoveryBatch: ( | 2821 | connectGoogleDiscoveryBatch: ( |
| 2769 | input: ConnectGoogleDiscoveryBatchInput, | 2822 | input: ConnectGoogleDiscoveryBatchInput, |
| 2770 | ) => Effect.Effect<ConnectGoogleDiscoveryBatchResult, Error, WorkspaceStorageServices>; | 2823 | ) => Effect.Effect<ConnectGoogleDiscoveryBatchResult, Error, ScopeStorageServices>; |
| 2771 | connectMcpSource: ( | 2824 | connectMcpSource: ( |
| 2772 | input: ConnectMcpSourceInput, | 2825 | input: ConnectMcpSourceInput, |
| 2773 | ) => Effect.Effect<McpSourceConnectResult, Error, WorkspaceStorageServices>; | 2826 | ) => Effect.Effect<McpSourceConnectResult, Error, ScopeStorageServices>; |
| 2774 | listWorkspaceOauthClients: (input: { | 2827 | listScopeOauthClients: (input: { |
| 2775 | workspaceId: WorkspaceId; | 2828 | scopeId: ScopeId; |
| 2776 | providerKey: string; | 2829 | providerKey: string; |
| 2777 | }) => Effect.Effect<readonly WorkspaceOauthClient[], Error, WorkspaceStorageServices>; | 2830 | }) => Effect.Effect<readonly ScopeOauthClient[], Error, ScopeStorageServices>; |
| 2778 | createWorkspaceOauthClient: ( | 2831 | createScopeOauthClient: ( |
| 2779 | input: CreateWorkspaceOauthClientInput, | 2832 | input: CreateScopeOauthClientInput, |
| 2780 | ) => Effect.Effect<WorkspaceOauthClient, Error, WorkspaceStorageServices>; | 2833 | ) => Effect.Effect<ScopeOauthClient, Error, ScopeStorageServices>; |
| 2781 | removeWorkspaceOauthClient: (input: { | 2834 | removeScopeOauthClient: (input: { |
| 2782 | workspaceId: WorkspaceId; | 2835 | scopeId: ScopeId; |
| 2783 | oauthClientId: WorkspaceOauthClient["id"]; | 2836 | oauthClientId: ScopeOauthClient["id"]; |
| 2784 | }) => Effect.Effect<boolean, Error, WorkspaceStorageServices>; | 2837 | }) => Effect.Effect<boolean, Error, ScopeStorageServices>; |
| 2785 | removeProviderAuthGrant: (input: { | 2838 | removeProviderAuthGrant: (input: { |
| 2786 | workspaceId: WorkspaceId; | 2839 | scopeId: ScopeId; |
| 2787 | grantId: ProviderAuthGrant["id"]; | 2840 | grantId: ProviderAuthGrant["id"]; |
| 2788 | }) => Effect.Effect<boolean, Error, WorkspaceStorageServices>; | 2841 | }) => Effect.Effect<boolean, Error, ScopeStorageServices>; |
| 2789 | startSourceOAuthSession: ( | 2842 | startSourceOAuthSession: ( |
| 2790 | input: StartSourceOAuthSessionInput, | 2843 | input: StartSourceOAuthSessionInput, |
| 2791 | ) => Effect.Effect<StartSourceOAuthSessionResult, Error, never>; | 2844 | ) => Effect.Effect<StartSourceOAuthSessionResult, Error, never>; |
| @@ -2794,24 +2847,24 @@ type RuntimeSourceAuthServiceShape = { · 2 unmodified lines | |||
| 2794 | code?: string | null; | 2847 | code?: string | null; |
| 2795 | error?: string | null; | 2848 | error?: string | null; |
| 2796 | errorDescription?: string | null; | 2849 | errorDescription?: string | null; |
| 2797 | }) => Effect.Effect<CompleteSourceOAuthSessionResult, Error, WorkspaceStorageServices>; | 2850 | }) => Effect.Effect<CompleteSourceOAuthSessionResult, Error, ScopeStorageServices>; |
| 2798 | completeProviderOauthCallback: (input: { | 2851 | completeProviderOauthCallback: (input: { |
| 2799 | workspaceId: WorkspaceId; | 2852 | scopeId: ScopeId; |
| 2800 | actorAccountId?: AccountId | null; | 2853 | actorScopeId?: ScopeId | null; |
| 2801 | state: string; | 2854 | state: string; |
| 2802 | code?: string | null; | 2855 | code?: string | null; |
| 2803 | error?: string | null; | 2856 | error?: string | null; |
| 2804 | errorDescription?: string | null; | 2857 | errorDescription?: string | null; |
| 2805 | }) => Effect.Effect<CompleteProviderOauthCallbackResult, Error, WorkspaceStorageServices>; | 2858 | }) => Effect.Effect<CompleteProviderOauthCallbackResult, Error, ScopeStorageServices>; |
| 2806 | completeSourceCredentialSetup: (input: { | 2859 | completeSourceCredentialSetup: (input: { |
| 2807 | workspaceId: WorkspaceId; | 2860 | scopeId: ScopeId; |
| 2808 | sourceId: Source["id"]; | 2861 | sourceId: Source["id"]; |
| 2809 | actorAccountId?: AccountId | null; | 2862 | actorScopeId?: ScopeId | null; |
| 2810 | state: string; | 2863 | state: string; |
| 2811 | code?: string | null; | 2864 | code?: string | null; |
| 2812 | error?: string | null; | 2865 | error?: string | null; |
| 2813 | errorDescription?: string | null; | 2866 | errorDescription?: string | null; |
| 2814 | }) => Effect.Effect<CompleteSourceCredentialSetupResult, Error, WorkspaceStorageServices>; | 2867 | }) => Effect.Effect<CompleteSourceCredentialSetupResult, Error, ScopeStorageServices>; |
| 2815 | }; | 2868 | }; |
| 2816 | 2869 | ||
| 2817 | type RuntimeSourceAuthDependencies = { | 2870 | type RuntimeSourceAuthDependencies = { |
| @@ -2823,10 +2876,10 @@ type RuntimeSourceAuthDependencies = { · 5 unmodified lines | |||
| 2823 | storeSecretMaterial: StoreSecretMaterial; | 2876 | storeSecretMaterial: StoreSecretMaterial; |
| 2824 | deleteSecretMaterial: DeleteSecretMaterial; | 2877 | deleteSecretMaterial: DeleteSecretMaterial; |
| 2825 | getLocalServerBaseUrl?: () => string | undefined; | 2878 | getLocalServerBaseUrl?: () => string | undefined; |
| 2826 | localWorkspaceState?: RuntimeLocalWorkspaceState; | 2879 | localScopeState?: RuntimeLocalScopeState; |
| 2827 | }; | 2880 | }; |
| 2828 | 2881 | ||
| 2829 | type ProvideLocalWorkspace = <A, E, R>( | 2882 | type ProvideLocalScope = <A, E, R>( |
| 2830 | effect: Effect.Effect<A, E, R>, | 2883 | effect: Effect.Effect<A, E, R>, |
| 2831 | ) => Effect.Effect<A, E, R>; | 2884 | ) => Effect.Effect<A, E, R>; |
| 2832 | 2885 | ||
| @@ -2836,9 +2889,9 @@ type RuntimeSourceConnectionServiceShape = Pick< · 3 unmodified lines | |||
| 2836 | | "addExecutorSource" | 2889 | | "addExecutorSource" |
| 2837 | | "connectGoogleDiscoveryBatch" | 2890 | | "connectGoogleDiscoveryBatch" |
| 2838 | | "connectMcpSource" | 2891 | | "connectMcpSource" |
| 2839 | | "listWorkspaceOauthClients" | 2892 | | "listScopeOauthClients" |
| 2840 | | "createWorkspaceOauthClient" | 2893 | | "createScopeOauthClient" |
| 2841 | | "removeWorkspaceOauthClient" | 2894 | | "removeScopeOauthClient" |
| 2842 | | "removeProviderAuthGrant" | 2895 | | "removeProviderAuthGrant" |
| 2843 | >; | 2896 | >; |
| 2844 | 2897 | ||
| @@ -2852,24 +2905,24 @@ type RuntimeSourceOAuthSessionServiceShape = Pick< · 7 unmodified lines | |||
| 2852 | 2905 | ||
| 2853 | const createRuntimeSourceConnectionService = ( | 2906 | const createRuntimeSourceConnectionService = ( |
| 2854 | input: RuntimeSourceAuthDependencies, | 2907 | input: RuntimeSourceAuthDependencies, |
| 2855 | provideLocalWorkspace: ProvideLocalWorkspace, | 2908 | provideLocalWorkspace: ProvideLocalScope, |
| 2856 | ): RuntimeSourceConnectionServiceShape => { | 2909 | ): RuntimeSourceConnectionServiceShape => { |
| 2857 | const mirrorLocalSourceResult = ( | 2910 | const mirrorLocalSourceResult = ( |
| 2858 | result: ExecutorSourceAddResult, | 2911 | result: ExecutorSourceAddResult, |
| 2859 | ): Effect.Effect<ExecutorSourceAddResult, Error, WorkspaceStorageServices> => | 2912 | ): Effect.Effect<ExecutorSourceAddResult, Error, ScopeStorageServices> => |
| 2860 | Effect.succeed(result); | 2913 | Effect.succeed(result); |
| 2861 | const mirrorLocalMcpSourceResult = ( | 2914 | const mirrorLocalMcpSourceResult = ( |
| 2862 | result: McpSourceConnectResult, | 2915 | result: McpSourceConnectResult, |
| 2863 | ): Effect.Effect<McpSourceConnectResult, Error, WorkspaceStorageServices> => | 2916 | ): Effect.Effect<McpSourceConnectResult, Error, ScopeStorageServices> => |
| 2864 | Effect.succeed(result); | 2917 | Effect.succeed(result); |
| 2865 | 2918 | ||
| 2866 | return { | 2919 | return { |
| 2867 | getSourceById: ({ workspaceId, sourceId, actorAccountId }) => | 2920 | getSourceById: ({ scopeId, sourceId, actorScopeId }) => |
| 2868 | provideLocalWorkspace( | 2921 | provideLocalWorkspace( |
| 2869 | input.sourceStore.loadSourceById({ | 2922 | input.sourceStore.loadSourceById({ |
| 2870 | workspaceId, | 2923 | scopeId, |
| 2871 | sourceId, | 2924 | sourceId, |
| 2872 | actorAccountId, | 2925 | actorScopeId, |
| 2873 | }), | 2926 | }), |
| 2874 | ), | 2927 | ), |
| 2875 | 2928 | ||
| @@ -2886,6 +2939,7 @@ const createRuntimeSourceConnectionService = ( · 10 unmodified lines | |||
| 2886 | resolveSecretMaterial: input.resolveSecretMaterial, | 2939 | resolveSecretMaterial: input.resolveSecretMaterial, |
| 2887 | getLocalServerBaseUrl: input.getLocalServerBaseUrl, | 2940 | getLocalServerBaseUrl: input.getLocalServerBaseUrl, |
| 2888 | baseUrl: options?.baseUrl, | 2941 | baseUrl: options?.baseUrl, |
| 2942 | localScopeState: input.localScopeState, | ||
| 2889 | }) | 2943 | }) |
| 2890 | : isExecutorHttpEndpointSourceInput(sourceInput) | 2944 | : isExecutorHttpEndpointSourceInput(sourceInput) |
| 2891 | ? addExecutorHttpSource({ | 2945 | ? addExecutorHttpSource({ |
| @@ -2898,6 +2952,7 @@ const createRuntimeSourceConnectionService = ( · 6 unmodified lines | |||
| 2898 | resolveSecretMaterial: input.resolveSecretMaterial, | 2952 | resolveSecretMaterial: input.resolveSecretMaterial, |
| 2899 | getLocalServerBaseUrl: input.getLocalServerBaseUrl, | 2953 | getLocalServerBaseUrl: input.getLocalServerBaseUrl, |
| 2900 | baseUrl: options?.baseUrl, | 2954 | baseUrl: options?.baseUrl, |
| 2955 | localScopeState: input.localScopeState, | ||
| 2901 | }) | 2956 | }) |
| 2902 | : isExecutorMcpSourceInput(sourceInput) | 2957 | : isExecutorMcpSourceInput(sourceInput) |
| 2903 | ? connectMcpSourceInternal({ | 2958 | ? connectMcpSourceInternal({ |
| @@ -2905,8 +2960,8 @@ const createRuntimeSourceConnectionService = ( · 1 unmodified line | |||
| 2905 | sourceStore: input.sourceStore, | 2960 | sourceStore: input.sourceStore, |
| 2906 | sourceCatalogSync: input.sourceCatalogSync, | 2961 | sourceCatalogSync: input.sourceCatalogSync, |
| 2907 | getLocalServerBaseUrl: input.getLocalServerBaseUrl, | 2962 | getLocalServerBaseUrl: input.getLocalServerBaseUrl, |
| 2908 | workspaceId: sourceInput.workspaceId, | 2963 | scopeId: sourceInput.scopeId, |
| 2909 | actorAccountId: sourceInput.actorAccountId, | 2964 | actorScopeId: sourceInput.actorScopeId, |
| 2910 | executionId: sourceInput.executionId, | 2965 | executionId: sourceInput.executionId, |
| 2911 | interactionId: sourceInput.interactionId, | 2966 | interactionId: sourceInput.interactionId, |
| 2912 | endpoint: sourceInput.endpoint, | 2967 | endpoint: sourceInput.endpoint, |
| @@ -2936,6 +2991,7 @@ const createRuntimeSourceConnectionService = ( · 23 unmodified lines | |||
| 2936 | sourceCatalogSync: input.sourceCatalogSync, | 2991 | sourceCatalogSync: input.sourceCatalogSync, |
| 2937 | sourceInput, | 2992 | sourceInput, |
| 2938 | getLocalServerBaseUrl: input.getLocalServerBaseUrl, | 2993 | getLocalServerBaseUrl: input.getLocalServerBaseUrl, |
| 2994 | localScopeState: input.localScopeState, | ||
| 2939 | }), | 2995 | }), |
| 2940 | ), | 2996 | ), |
| 2941 | 2997 | ||
| @@ -2946,8 +3002,8 @@ const createRuntimeSourceConnectionService = ( · 4 unmodified lines | |||
| 2946 | sourceStore: input.sourceStore, | 3002 | sourceStore: input.sourceStore, |
| 2947 | sourceCatalogSync: input.sourceCatalogSync, | 3003 | sourceCatalogSync: input.sourceCatalogSync, |
| 2948 | getLocalServerBaseUrl: input.getLocalServerBaseUrl, | 3004 | getLocalServerBaseUrl: input.getLocalServerBaseUrl, |
| 2949 | workspaceId: sourceInput.workspaceId, | 3005 | scopeId: sourceInput.scopeId, |
| 2950 | actorAccountId: sourceInput.actorAccountId, | 3006 | actorScopeId: sourceInput.actorScopeId, |
| 2951 | sourceId: sourceInput.sourceId, | 3007 | sourceId: sourceInput.sourceId, |
| 2952 | executionId: null, | 3008 | executionId: null, |
| 2953 | interactionId: null, | 3009 | interactionId: null, |
| @@ -2969,54 +3025,71 @@ const createRuntimeSourceConnectionService = ( · 15 unmodified lines | |||
| 2969 | ), | 3025 | ), |
| 2970 | ), | 3026 | ), |
| 2971 | 3027 | ||
| 2972 | listWorkspaceOauthClients: ({ workspaceId, providerKey }) => | 3028 | listScopeOauthClients: ({ scopeId, providerKey }) => |
| 2973 | provideLocalWorkspace( | 3029 | provideLocalWorkspace( |
| 2974 | input.executorState.workspaceOauthClients.listByWorkspaceAndProvider({ | 3030 | Effect.gen(function* () { |
| 2975 | workspaceId, | 3031 | const scopeIds = resolvedScopeSearchOrder({ |
| 2976 | providerKey, | 3032 | scopeId, |
| 3033 | localScopeState: input.localScopeState, | ||
| 3034 | }); | ||
| 3035 | const clientsById = new Map<ScopeOauthClient["id"], ScopeOauthClient>(); | ||
| 3036 | |||
| 3037 | for (const candidateScopeId of scopeIds) { | ||
| 3038 | const clients = yield* input.executorState.scopeOauthClients.listByScopeAndProvider({ | ||
| 3039 | scopeId: candidateScopeId, | ||
| 3040 | providerKey, | ||
| 3041 | }); | ||
| 3042 | for (const client of clients) { | ||
| 3043 | if (!clientsById.has(client.id)) { | ||
| 3044 | clientsById.set(client.id, client); | ||
| 3045 | } | ||
| 3046 | } | ||
| 3047 | } | ||
| 3048 | |||
| 3049 | return [...clientsById.values()]; | ||
| 2977 | }), | 3050 | }), |
| 2978 | ), | 3051 | ), |
| 2979 | 3052 | ||
| 2980 | createWorkspaceOauthClient: ({ workspaceId, providerKey, label, oauthClient }) => | 3053 | createScopeOauthClient: ({ scopeId, providerKey, label, oauthClient }) => |
| 2981 | provideLocalWorkspace( | 3054 | provideLocalWorkspace( |
| 2982 | Effect.gen(function* () { | 3055 | Effect.gen(function* () { |
| 2983 | const sourceAdapter = findSourceAdapterByProviderKey(providerKey); | 3056 | const sourceAdapter = findSourceAdapterByProviderKey(providerKey); |
| 2984 | const created = yield* createWorkspaceOauthClient({ | 3057 | const created = yield* createScopeOauthClient({ |
| 2985 | executorState: input.executorState, | 3058 | executorState: input.executorState, |
| 2986 | workspaceId, | 3059 | scopeId, |
| 2987 | providerKey, | 3060 | providerKey, |
| 2988 | oauthClient, | 3061 | oauthClient, |
| 2989 | label, | 3062 | label, |
| 2990 | normalizeOauthClient: sourceAdapter?.normalizeOauthClientInput, | 3063 | normalizeOauthClient: sourceAdapter?.normalizeOauthClientInput, |
| 2991 | storeSecretMaterial: input.storeSecretMaterial, | 3064 | storeSecretMaterial: input.storeSecretMaterial, |
| 2992 | }); | 3065 | }); |
| 2993 | const stored = yield* input.executorState.workspaceOauthClients.getById(created.id); | 3066 | const stored = yield* input.executorState.scopeOauthClients.getById(created.id); |
| 2994 | if (Option.isNone(stored)) { | 3067 | if (Option.isNone(stored)) { |
| 2995 | return yield* runtimeEffectError("sources/source-auth-service", `Workspace OAuth client ${created.id} was not persisted`); | 3068 | return yield* runtimeEffectError("sources/source-auth-service", `Scope OAuth client ${created.id} was not persisted`); |
| 2996 | } | 3069 | } |
| 2997 | 3070 | ||
| 2998 | return stored.value; | 3071 | return stored.value; |
| 2999 | }), | 3072 | }), |
| 3000 | ), | 3073 | ), |
| 3001 | 3074 | ||
| 3002 | removeWorkspaceOauthClient: ({ workspaceId, oauthClientId }) => | 3075 | removeScopeOauthClient: ({ scopeId, oauthClientId }) => |
| 3003 | provideLocalWorkspace( | 3076 | provideLocalWorkspace( |
| 3004 | Effect.gen(function* () { | 3077 | Effect.gen(function* () { |
| 3005 | const oauthClient = yield* input.executorState.workspaceOauthClients.getById(oauthClientId); | 3078 | const oauthClient = yield* input.executorState.scopeOauthClients.getById(oauthClientId); |
| 3006 | if (Option.isNone(oauthClient) || oauthClient.value.workspaceId !== workspaceId) { | 3079 | if (Option.isNone(oauthClient) || oauthClient.value.scopeId !== scopeId) { |
| 3007 | return false; | 3080 | return false; |
| 3008 | } | 3081 | } |
| 3009 | 3082 | ||
| 3010 | const grants = yield* input.executorState.providerAuthGrants.listByWorkspaceId(workspaceId); | 3083 | const grants = yield* input.executorState.providerAuthGrants.listByScopeId(scopeId); |
| 3011 | const dependentGrant = grants.find((grant) => grant.oauthClientId === oauthClientId); | 3084 | const dependentGrant = grants.find((grant) => grant.oauthClientId === oauthClientId); |
| 3012 | if (dependentGrant) { | 3085 | if (dependentGrant) { |
| 3013 | return yield* runtimeEffectError("sources/source-auth-service", | 3086 | return yield* runtimeEffectError("sources/source-auth-service", |
| 3014 | `Workspace OAuth client ${oauthClientId} is still referenced by provider grant ${dependentGrant.id}`, | 3087 | `Scope OAuth client ${oauthClientId} is still referenced by provider grant ${dependentGrant.id}`, |
| 3015 | ); | 3088 | ); |
| 3016 | } | 3089 | } |
| 3017 | 3090 | ||
| 3018 | const secretRef = sourceOauthClientSecretRef(oauthClient.value); | 3091 | const secretRef = sourceOauthClientSecretRef(oauthClient.value); |
| 3019 | const removed = yield* input.executorState.workspaceOauthClients.removeById(oauthClientId); | 3092 | const removed = yield* input.executorState.scopeOauthClients.removeById(oauthClientId); |
| 3020 | if (removed && secretRef) { | 3093 | if (removed && secretRef) { |
| 3021 | yield* input.deleteSecretMaterial(secretRef).pipe( | 3094 | yield* input.deleteSecretMaterial(secretRef).pipe( |
| 3022 | Effect.either, | 3095 | Effect.either, |
| @@ -3028,12 +3101,12 @@ const createRuntimeSourceConnectionService = ( · 5 unmodified lines | |||
| 3028 | }), | 3101 | }), |
| 3029 | ), | 3102 | ), |
| 3030 | 3103 | ||
| 3031 | removeProviderAuthGrant: ({ workspaceId, grantId }) => | 3104 | removeProviderAuthGrant: ({ scopeId, grantId }) => |
| 3032 | provideLocalWorkspace( | 3105 | provideLocalWorkspace( |
| 3033 | removeProviderAuthGrantInternal({ | 3106 | removeProviderAuthGrantInternal({ |
| 3034 | executorState: input.executorState, | 3107 | executorState: input.executorState, |
| 3035 | sourceStore: input.sourceStore, | 3108 | sourceStore: input.sourceStore, |
| 3036 | workspaceId, | 3109 | scopeId, |
| 3037 | grantId, | 3110 | grantId, |
| 3038 | deleteSecretMaterial: input.deleteSecretMaterial, | 3111 | deleteSecretMaterial: input.deleteSecretMaterial, |
| 3039 | }), | 3112 | }), |
| @@ -3043,7 +3116,7 @@ const createRuntimeSourceConnectionService = ( · 3 unmodified lines | |||
| 3043 | 3116 | ||
| 3044 | const createRuntimeSourceOAuthSessionService = ( | 3117 | const createRuntimeSourceOAuthSessionService = ( |
| 3045 | input: RuntimeSourceAuthDependencies, | 3118 | input: RuntimeSourceAuthDependencies, |
| 3046 | provideLocalWorkspace: ProvideLocalWorkspace, | 3119 | provideLocalWorkspace: ProvideLocalScope, |
| 3047 | ): RuntimeSourceOAuthSessionServiceShape => ({ | 3120 | ): RuntimeSourceOAuthSessionServiceShape => ({ |
| 3048 | startSourceOAuthSession: (oauthInput) => | 3121 | startSourceOAuthSession: (oauthInput) => |
| 3049 | Effect.gen(function* () { | 3122 | Effect.gen(function* () { |
| @@ -3069,9 +3142,9 @@ const createRuntimeSourceOAuthSessionService = ( · 19 unmodified lines | |||
| 3069 | 3142 | ||
| 3070 | yield* input.executorState.sourceAuthSessions.upsert({ | 3143 | yield* input.executorState.sourceAuthSessions.upsert({ |
| 3071 | id: sessionId, | 3144 | id: sessionId, |
| 3072 | workspaceId: oauthInput.workspaceId, | 3145 | scopeId: oauthInput.scopeId, |
| 3073 | sourceId: SourceIdSchema.make(`oauth_draft_${crypto.randomUUID()}`), | 3146 | sourceId: SourceIdSchema.make(`oauth_draft_${crypto.randomUUID()}`), |
| 3074 | actorAccountId: oauthInput.actorAccountId ?? null, | 3147 | actorScopeId: oauthInput.actorScopeId ?? null, |
| 3075 | credentialSlot: "runtime", | 3148 | credentialSlot: "runtime", |
| 3076 | executionId: null, | 3149 | executionId: null, |
| 3077 | interactionId: null, | 3150 | interactionId: null, |
| @@ -3215,7 +3288,7 @@ const createRuntimeSourceOAuthSessionService = ( · 137 unmodified lines | |||
| 3215 | } satisfies CompleteSourceOAuthSessionResult; | 3288 | } satisfies CompleteSourceOAuthSessionResult; |
| 3216 | })), | 3289 | })), |
| 3217 | 3290 | ||
| 3218 | completeProviderOauthCallback: ({ workspaceId, actorAccountId, state, code, error, errorDescription }) => | 3291 | completeProviderOauthCallback: ({ scopeId, actorScopeId, state, code, error, errorDescription }) => |
| 3219 | provideLocalWorkspace(Effect.gen(function* () { | 3292 | provideLocalWorkspace(Effect.gen(function* () { |
| 3220 | const sessionOption = yield* input.executorState.sourceAuthSessions.getByState(state); | 3293 | const sessionOption = yield* input.executorState.sourceAuthSessions.getByState(state); |
| 3221 | if (Option.isNone(sessionOption)) { | 3294 | if (Option.isNone(sessionOption)) { |
| @@ -3223,10 +3296,10 @@ const createRuntimeSourceOAuthSessionService = ( · 1 unmodified line | |||
| 3223 | } | 3296 | } |
| 3224 | 3297 | ||
| 3225 | const session = sessionOption.value; | 3298 | const session = sessionOption.value; |
| 3226 | if (session.workspaceId !== workspaceId) { | 3299 | if (session.scopeId !== scopeId) { |
| 3227 | return yield* runtimeEffectError("sources/source-auth-service", `Source auth session ${session.id} does not match workspaceId=${workspaceId}`); | 3300 | return yield* runtimeEffectError("sources/source-auth-service", `Source auth session ${session.id} does not match scopeId=${scopeId}`); |
| 3228 | } | 3301 | } |
| 3229 | if ((session.actorAccountId ?? null) !== (actorAccountId ?? null)) { | 3302 | if ((session.actorScopeId ?? null) !== (actorScopeId ?? null)) { |
| 3230 | return yield* runtimeEffectError("sources/source-auth-service", `Source auth session ${session.id} does not match the active account`); | 3303 | return yield* runtimeEffectError("sources/source-auth-service", `Source auth session ${session.id} does not match the active account`); |
| 3231 | } | 3304 | } |
| 3232 | if (session.providerKind !== "oauth2_provider_batch") { | 3305 | if (session.providerKind !== "oauth2_provider_batch") { |
| @@ -3238,9 +3311,9 @@ const createRuntimeSourceOAuthSessionService = ( · 5 unmodified lines | |||
| 3238 | sessionData.targetSources, | 3311 | sessionData.targetSources, |
| 3239 | (target) => | 3312 | (target) => |
| 3240 | input.sourceStore.loadSourceById({ | 3313 | input.sourceStore.loadSourceById({ |
| 3241 | workspaceId, | 3314 | scopeId, |
| 3242 | sourceId: target.sourceId, | 3315 | sourceId: target.sourceId, |
| 3243 | actorAccountId, | 3316 | actorScopeId, |
| 3244 | }), | 3317 | }), |
| 3245 | { discard: false }, | 3318 | { discard: false }, |
| 3246 | ); | 3319 | ); |
| @@ -3276,14 +3349,15 @@ const createRuntimeSourceOAuthSessionService = ( · 29 unmodified lines | |||
| 3276 | return yield* runtimeEffectError("sources/source-auth-service", "OAuth session is missing the PKCE code verifier"); | 3349 | return yield* runtimeEffectError("sources/source-auth-service", "OAuth session is missing the PKCE code verifier"); |
| 3277 | } | 3350 | } |
| 3278 | 3351 | ||
| 3279 | const oauthClient = yield* resolveWorkspaceOauthClientById({ | 3352 | const oauthClient = yield* resolveScopeOauthClientById({ |
| 3280 | executorState: input.executorState, | 3353 | executorState: input.executorState, |
| 3281 | workspaceId, | 3354 | scopeId, |
| 3282 | oauthClientId: sessionData.oauthClientId, | 3355 | oauthClientId: sessionData.oauthClientId, |
| 3283 | providerKey: sessionData.providerKey, | 3356 | providerKey: sessionData.providerKey, |
| 3357 | localScopeState: input.localScopeState, | ||
| 3284 | }); | 3358 | }); |
| 3285 | if (oauthClient === null) { | 3359 | if (oauthClient === null) { |
| 3286 | return yield* runtimeEffectError("sources/source-auth-service", `Workspace OAuth client not found: ${sessionData.oauthClientId}`); | 3360 | return yield* runtimeEffectError("sources/source-auth-service", `Scope OAuth client not found: ${sessionData.oauthClientId}`); |
| 3287 | } | 3361 | } |
| 3288 | 3362 | ||
| 3289 | let clientSecret: string | null = null; | 3363 | let clientSecret: string | null = null; |
| @@ -3303,9 +3377,9 @@ const createRuntimeSourceOAuthSessionService = ( · 13 unmodified lines | |||
| 3303 | code: authorizationCode, | 3377 | code: authorizationCode, |
| 3304 | }); | 3378 | }); |
| 3305 | 3379 | ||
| 3306 | const availableGrants = yield* input.executorState.providerAuthGrants.listByWorkspaceActorAndProvider({ | 3380 | const availableGrants = yield* input.executorState.providerAuthGrants.listByScopeActorAndProvider({ |
| 3307 | workspaceId, | 3381 | scopeId, |
| 3308 | actorAccountId: actorAccountId ?? null, | 3382 | actorScopeId: actorScopeId ?? null, |
| 3309 | providerKey: sessionData.providerKey, | 3383 | providerKey: sessionData.providerKey, |
| 3310 | }); | 3384 | }); |
| 3311 | const existingGrant = availableGrants.find( | 3385 | const existingGrant = availableGrants.find( |
| @@ -3319,8 +3393,8 @@ const createRuntimeSourceOAuthSessionService = ( · 7 unmodified lines | |||
| 3319 | ); | 3393 | ); |
| 3320 | const nextGrant = yield* upsertProviderAuthGrant({ | 3394 | const nextGrant = yield* upsertProviderAuthGrant({ |
| 3321 | executorState: input.executorState, | 3395 | executorState: input.executorState, |
| 3322 | workspaceId, | 3396 | scopeId, |
| 3323 | actorAccountId, | 3397 | actorScopeId, |
| 3324 | providerKey: sessionData.providerKey, | 3398 | providerKey: sessionData.providerKey, |
| 3325 | oauthClientId: sessionData.oauthClientId, | 3399 | oauthClientId: sessionData.oauthClientId, |
| 3326 | tokenEndpoint: sessionData.tokenEndpoint, | 3400 | tokenEndpoint: sessionData.tokenEndpoint, |
| @@ -3339,9 +3413,9 @@ const createRuntimeSourceOAuthSessionService = ( · 12 unmodified lines | |||
| 3339 | (target) => | 3413 | (target) => |
| 3340 | Effect.map( | 3414 | Effect.map( |
| 3341 | input.sourceStore.loadSourceById({ | 3415 | input.sourceStore.loadSourceById({ |
| 3342 | workspaceId, | 3416 | scopeId, |
| 3343 | sourceId: target.sourceId, | 3417 | sourceId: target.sourceId, |
| 3344 | actorAccountId, | 3418 | actorScopeId, |
| 3345 | }), | 3419 | }), |
| 3346 | (source) => ({ | 3420 | (source) => ({ |
| 3347 | source, | 3421 | source, |
| @@ -3354,7 +3428,7 @@ const createRuntimeSourceOAuthSessionService = ( · 6 unmodified lines | |||
| 3354 | const connectedSources = yield* attachProviderGrantToSources({ | 3428 | const connectedSources = yield* attachProviderGrantToSources({ |
| 3355 | sourceStore: input.sourceStore, | 3429 | sourceStore: input.sourceStore, |
| 3356 | sourceCatalogSync: input.sourceCatalogSync, | 3430 | sourceCatalogSync: input.sourceCatalogSync, |
| 3357 | actorAccountId, | 3431 | actorScopeId, |
| 3358 | grantId: nextGrant.id, | 3432 | grantId: nextGrant.id, |
| 3359 | providerKey: nextGrant.providerKey, | 3433 | providerKey: nextGrant.providerKey, |
| 3360 | headerName: nextGrant.headerName, | 3434 | headerName: nextGrant.headerName, |
| @@ -3384,7 +3458,7 @@ const createRuntimeSourceOAuthSessionService = ( · 23 unmodified lines | |||
| 3384 | } satisfies CompleteProviderOauthCallbackResult; | 3458 | } satisfies CompleteProviderOauthCallbackResult; |
| 3385 | })), | 3459 | })), |
| 3386 | 3460 | ||
| 3387 | completeSourceCredentialSetup: ({ workspaceId, sourceId, actorAccountId, state, code, error, errorDescription }) => | 3461 | completeSourceCredentialSetup: ({ scopeId, sourceId, actorScopeId, state, code, error, errorDescription }) => |
| 3388 | provideLocalWorkspace(Effect.gen(function* () { | 3462 | provideLocalWorkspace(Effect.gen(function* () { |
| 3389 | const sessionOption = yield* input.executorState.sourceAuthSessions.getByState(state); | 3463 | const sessionOption = yield* input.executorState.sourceAuthSessions.getByState(state); |
| 3390 | if (Option.isNone(sessionOption)) { | 3464 | if (Option.isNone(sessionOption)) { |
| @@ -3392,22 +3466,22 @@ const createRuntimeSourceOAuthSessionService = ( · 1 unmodified line | |||
| 3392 | } | 3466 | } |
| 3393 | 3467 | ||
| 3394 | const session = sessionOption.value; | 3468 | const session = sessionOption.value; |
| 3395 | if (session.workspaceId !== workspaceId || session.sourceId !== sourceId) { | 3469 | if (session.scopeId !== scopeId || session.sourceId !== sourceId) { |
| 3396 | return yield* runtimeEffectError("sources/source-auth-service", | 3470 | return yield* runtimeEffectError("sources/source-auth-service", |
| 3397 | `Source auth session ${session.id} does not match workspaceId=${workspaceId} sourceId=${sourceId}`, | 3471 | `Source auth session ${session.id} does not match scopeId=${scopeId} sourceId=${sourceId}`, |
| 3398 | ); | 3472 | ); |
| 3399 | } | 3473 | } |
| 3400 | if ( | 3474 | if ( |
| 3401 | actorAccountId !== undefined | 3475 | actorScopeId !== undefined |
| 3402 | && (session.actorAccountId ?? null) !== (actorAccountId ?? null) | 3476 | && (session.actorScopeId ?? null) !== (actorScopeId ?? null) |
| 3403 | ) { | 3477 | ) { |
| 3404 | return yield* runtimeEffectError("sources/source-auth-service", `Source auth session ${session.id} does not match the active account`); | 3478 | return yield* runtimeEffectError("sources/source-auth-service", `Source auth session ${session.id} does not match the active account`); |
| 3405 | } | 3479 | } |
| 3406 | 3480 | ||
| 3407 | const source = yield* input.sourceStore.loadSourceById({ | 3481 | const source = yield* input.sourceStore.loadSourceById({ |
| 3408 | workspaceId: session.workspaceId, | 3482 | scopeId: session.scopeId, |
| 3409 | sourceId: session.sourceId, | 3483 | sourceId: session.sourceId, |
| 3410 | actorAccountId: session.actorAccountId, | 3484 | actorScopeId: session.actorScopeId, |
| 3411 | }); | 3485 | }); |
| 3412 | 3486 | ||
| 3413 | if (session.status === "completed") { | 3487 | if (session.status === "completed") { |
| @@ -3439,13 +3513,13 @@ const createRuntimeSourceOAuthSessionService = ( · 25 unmodified lines | |||
| 3439 | }), | 3513 | }), |
| 3440 | ); | 3514 | ); |
| 3441 | const failedSource = yield* updateSourceStatus(input.sourceStore, source, { | 3515 | const failedSource = yield* updateSourceStatus(input.sourceStore, source, { |
| 3442 | actorAccountId: session.actorAccountId, | 3516 | actorScopeId: session.actorScopeId, |
| 3443 | status: "error", | 3517 | status: "error", |
| 3444 | lastError: reason, | 3518 | lastError: reason, |
| 3445 | }); | 3519 | }); |
| 3446 | yield* input.sourceCatalogSync.sync({ | 3520 | yield* input.sourceCatalogSync.sync({ |
| 3447 | source: failedSource, | 3521 | source: failedSource, |
| 3448 | actorAccountId: session.actorAccountId, | 3522 | actorScopeId: session.actorScopeId, |
| 3449 | }); | 3523 | }); |
| 3450 | yield* completeLiveInteraction({ | 3524 | yield* completeLiveInteraction({ |
| 3451 | executorState: input.executorState, | 3525 | executorState: input.executorState, |
| @@ -3503,7 +3577,7 @@ const createRuntimeSourceOAuthSessionService = ( · 51 unmodified lines | |||
| 3503 | ? exchanged.scope!.split(/\s+/).filter((scope) => scope.length > 0) | 3577 | ? exchanged.scope!.split(/\s+/).filter((scope) => scope.length > 0) |
| 3504 | : [...oauthSessionData.scopes]; | 3578 | : [...oauthSessionData.scopes]; |
| 3505 | connectedSource = yield* updateSourceStatus(input.sourceStore, source, { | 3579 | connectedSource = yield* updateSourceStatus(input.sourceStore, source, { |
| 3506 | actorAccountId: session.actorAccountId, | 3580 | actorScopeId: session.actorScopeId, |
| 3507 | status: "connected", | 3581 | status: "connected", |
| 3508 | lastError: null, | 3582 | lastError: null, |
| 3509 | auth: { | 3583 | auth: { |
| @@ -3518,10 +3592,10 @@ const createRuntimeSourceOAuthSessionService = ( · 8 unmodified lines | |||
| 3518 | grantSet: grantedScopes, | 3592 | grantSet: grantedScopes, |
| 3519 | }, | 3593 | }, |
| 3520 | }); | 3594 | }); |
| 3521 | const authArtifact = yield* input.executorState.authArtifacts.getByWorkspaceSourceAndActor({ | 3595 | const authArtifact = yield* input.executorState.authArtifacts.getByScopeSourceAndActor({ |
| 3522 | workspaceId: connectedSource.workspaceId, | 3596 | scopeId: connectedSource.scopeId, |
| 3523 | sourceId: connectedSource.id, | 3597 | sourceId: connectedSource.id, |
| 3524 | actorAccountId: session.actorAccountId ?? null, | 3598 | actorScopeId: session.actorScopeId ?? null, |
| 3525 | slot: "runtime", | 3599 | slot: "runtime", |
| 3526 | }); | 3600 | }); |
| 3527 | if (Option.isSome(authArtifact)) { | 3601 | if (Option.isSome(authArtifact)) { |
| @@ -3583,7 +3657,7 @@ const createRuntimeSourceOAuthSessionService = ( · 55 unmodified lines | |||
| 3583 | : null; | 3657 | : null; |
| 3584 | 3658 | ||
| 3585 | connectedSource = yield* updateSourceStatus(input.sourceStore, source, { | 3659 | connectedSource = yield* updateSourceStatus(input.sourceStore, source, { |
| 3586 | actorAccountId: session.actorAccountId, | 3660 | actorScopeId: session.actorScopeId, |
| 3587 | status: "connected", | 3661 | status: "connected", |
| 3588 | lastError: null, | 3662 | lastError: null, |
| 3589 | auth: createPersistedMcpOAuthSourceAuth({ | 3663 | auth: createPersistedMcpOAuthSourceAuth({ |
| @@ -3628,13 +3702,13 @@ const createRuntimeSourceOAuthSessionService = ( · 38 unmodified lines | |||
| 3628 | const indexed = yield* Effect.either( | 3702 | const indexed = yield* Effect.either( |
| 3629 | input.sourceCatalogSync.sync({ | 3703 | input.sourceCatalogSync.sync({ |
| 3630 | source: connectedSource, | 3704 | source: connectedSource, |
| 3631 | actorAccountId: session.actorAccountId, | 3705 | actorScopeId: session.actorScopeId, |
| 3632 | }), | 3706 | }), |
| 3633 | ); | 3707 | ); |
| 3634 | yield* Either.match(indexed, { | 3708 | yield* Either.match(indexed, { |
| 3635 | onLeft: (error) => | 3709 | onLeft: (error) => |
| 3636 | updateSourceStatus(input.sourceStore, connectedSource, { | 3710 | updateSourceStatus(input.sourceStore, connectedSource, { |
| 3637 | actorAccountId: session.actorAccountId, | 3711 | actorScopeId: session.actorScopeId, |
| 3638 | status: "error", | 3712 | status: "error", |
| 3639 | lastError: error.message, | 3713 | lastError: error.message, |
| 3640 | }).pipe( | 3714 | }).pipe( |
| @@ -3660,8 +3734,8 @@ const createRuntimeSourceOAuthSessionService = ( · 19 unmodified lines | |||
| 3660 | }); | 3734 | }); |
| 3661 | 3735 | ||
| 3662 | export const createRuntimeSourceAuthService = (input: RuntimeSourceAuthDependencies) => { | 3736 | export const createRuntimeSourceAuthService = (input: RuntimeSourceAuthDependencies) => { |
| 3663 | const provideLocalWorkspace: ProvideLocalWorkspace = (effect) => | 3737 | const provideLocalWorkspace: ProvideLocalScope = (effect) => |
| 3664 | provideOptionalRuntimeLocalWorkspace(effect, input.localWorkspaceState); | 3738 | provideOptionalRuntimeLocalScope(effect, input.localScopeState); |
| 3665 | const sourceConnection = createRuntimeSourceConnectionService( | 3739 | const sourceConnection = createRuntimeSourceConnectionService( |
| 3666 | input, | 3740 | input, |
| 3667 | provideLocalWorkspace, | 3741 | provideLocalWorkspace, |
| @@ -3704,7 +3778,7 @@ export const RuntimeSourceAuthServiceLive = (input: { · 36 unmodified lines | |||
| 3704 | const resolveSecretMaterial = yield* SecretMaterialResolverService; | 3778 | const resolveSecretMaterial = yield* SecretMaterialResolverService; |
| 3705 | const storeSecretMaterial = yield* SecretMaterialStorerService; | 3779 | const storeSecretMaterial = yield* SecretMaterialStorerService; |
| 3706 | const deleteSecretMaterial = yield* SecretMaterialDeleterService; | 3780 | const deleteSecretMaterial = yield* SecretMaterialDeleterService; |
| 3707 | const runtimeLocalWorkspace = yield* getRuntimeLocalWorkspaceOption(); | 3781 | const runtimeLocalScope = yield* getRuntimeLocalScopeOption(); |
| 3708 | 3782 | ||
| 3709 | return createRuntimeSourceAuthService({ | 3783 | return createRuntimeSourceAuthService({ |
| 3710 | executorState, | 3784 | executorState, |
| @@ -3715,7 +3789,7 @@ export const RuntimeSourceAuthServiceLive = (input: { · 4 unmodified lines | |||
| 3715 | storeSecretMaterial, | 3789 | storeSecretMaterial, |
| 3716 | deleteSecretMaterial, | 3790 | deleteSecretMaterial, |
| 3717 | getLocalServerBaseUrl: input.getLocalServerBaseUrl, | 3791 | getLocalServerBaseUrl: input.getLocalServerBaseUrl, |
| 3718 | localWorkspaceState: runtimeLocalWorkspace ?? undefined, | 3792 | localScopeState: runtimeLocalScope ?? undefined, |
| 3719 | }); | 3793 | }); |
| 3720 | }), | 3794 | }), |
| 3721 | ); | 3795 | ); |
| @@ -1,4 +1,7 @@ | |||
| 1 | import { SecretRefSchema, type SecretRef } from "#schema"; | 1 | import { |
| 2 | SecretRefSchema, | ||
| 3 | type SecretRef, | ||
| 4 | } from "#schema"; | ||
| 2 | import * as Schema from "effect/Schema"; | 5 | import * as Schema from "effect/Schema"; |
| 3 | 6 | ||
| 4 | export const SourceCredentialSelectionContentSchema = Schema.Union( | 7 | export const SourceCredentialSelectionContentSchema = Schema.Union( |
| @@ -1,11 +1,15 @@ | |||
| 1 | import { describe, expect, it } from "@effect/vitest"; | 1 | import { |
| 2 | describe, | ||
| 3 | expect, | ||
| 4 | it, | ||
| 5 | } from "@effect/vitest"; | ||
| 2 | import * as Effect from "effect/Effect"; | 6 | import * as Effect from "effect/Effect"; |
| 3 | 7 | ||
| 4 | import { | 8 | import { |
| 5 | CredentialIdSchema, | 9 | CredentialIdSchema, |
| 6 | decodeBuiltInAuthArtifactConfig, | 10 | decodeBuiltInAuthArtifactConfig, |
| 7 | SourceIdSchema, | 11 | SourceIdSchema, |
| 8 | WorkspaceIdSchema, | 12 | ScopeIdSchema, |
| 9 | type Source, | 13 | type Source, |
| 10 | } from "#schema"; | 14 | } from "#schema"; |
| 11 | 15 | ||
| @@ -17,7 +21,9 @@ import { · 5 unmodified lines | |||
| 17 | stableSourceCatalogRevisionId, | 21 | stableSourceCatalogRevisionId, |
| 18 | updateSourceFromPayload, | 22 | updateSourceFromPayload, |
| 19 | } from "./source-definitions"; | 23 | } from "./source-definitions"; |
| 20 | import { namespaceFromSourceName } from "./source-names"; | 24 | import { |
| 25 | namespaceFromSourceName, | ||
| 26 | } from "./source-names"; | ||
| 21 | 27 | ||
| 22 | const openApiBinding = ( | 28 | const openApiBinding = ( |
| 23 | specUrl = "https://api.github.com/openapi.json", | 29 | specUrl = "https://api.github.com/openapi.json", |
| @@ -81,7 +87,7 @@ const mcpBinding = ( · 57 unmodified lines | |||
| 81 | 87 | ||
| 82 | const makeSource = (overrides: Partial<Source> = {}): Source => ({ | 88 | const makeSource = (overrides: Partial<Source> = {}): Source => ({ |
| 83 | id: SourceIdSchema.make("src_source_definitions"), | 89 | id: SourceIdSchema.make("src_source_definitions"), |
| 84 | workspaceId: WorkspaceIdSchema.make("ws_source_definitions"), | 90 | scopeId: ScopeIdSchema.make("ws_source_definitions"), |
| 85 | name: "GitHub", | 91 | name: "GitHub", |
| 86 | kind: "openapi", | 92 | kind: "openapi", |
| 87 | endpoint: "https://api.github.com", | 93 | endpoint: "https://api.github.com", |
| @@ -108,7 +114,7 @@ describe("source-definitions", () => { · 20 unmodified lines | |||
| 108 | name: "Renamed GitHub", | 114 | name: "Renamed GitHub", |
| 109 | }); | 115 | }); |
| 110 | const differentWorkspace = makeSource({ | 116 | const differentWorkspace = makeSource({ |
| 111 | workspaceId: WorkspaceIdSchema.make("ws_source_definitions_other"), | 117 | scopeId: ScopeIdSchema.make("ws_source_definitions_other"), |
| 112 | }); | 118 | }); |
| 113 | 119 | ||
| 114 | expect(stableSourceCatalogId(source)).toBe(stableSourceCatalogId(source)); | 120 | expect(stableSourceCatalogId(source)).toBe(stableSourceCatalogId(source)); |
| @@ -151,7 +157,7 @@ describe("source-definitions", () => { · 36 unmodified lines | |||
| 151 | () => | 157 | () => |
| 152 | Effect.gen(function* () { | 158 | Effect.gen(function* () { |
| 153 | const source = yield* createSourceFromPayload({ | 159 | const source = yield* createSourceFromPayload({ |
| 154 | workspaceId: WorkspaceIdSchema.make("ws_create_defaults"), | 160 | scopeId: ScopeIdSchema.make("ws_create_defaults"), |
| 155 | sourceId: SourceIdSchema.make("src_create_defaults"), | 161 | sourceId: SourceIdSchema.make("src_create_defaults"), |
| 156 | payload: { | 162 | payload: { |
| 157 | name: " GitHub ", | 163 | name: " GitHub ", |
| @@ -216,7 +222,7 @@ describe("source-definitions", () => { · 58 unmodified lines | |||
| 216 | () => | 222 | () => |
| 217 | Effect.gen(function* () { | 223 | Effect.gen(function* () { |
| 218 | const source = yield* createSourceFromPayload({ | 224 | const source = yield* createSourceFromPayload({ |
| 219 | workspaceId: WorkspaceIdSchema.make("ws_create_oauth_defaults"), | 225 | scopeId: ScopeIdSchema.make("ws_create_oauth_defaults"), |
| 220 | sourceId: SourceIdSchema.make("src_create_oauth_defaults"), | 226 | sourceId: SourceIdSchema.make("src_create_oauth_defaults"), |
| 221 | payload: { | 227 | payload: { |
| 222 | name: "GraphQL Demo", | 228 | name: "GraphQL Demo", |
| @@ -253,7 +259,7 @@ describe("source-definitions", () => { · 30 unmodified lines | |||
| 253 | Effect.gen(function* () { | 259 | Effect.gen(function* () { |
| 254 | const invalidBearer = yield* Effect.flip( | 260 | const invalidBearer = yield* Effect.flip( |
| 255 | createSourceFromPayload({ | 261 | createSourceFromPayload({ |
| 256 | workspaceId: WorkspaceIdSchema.make("ws_invalid_bearer"), | 262 | scopeId: ScopeIdSchema.make("ws_invalid_bearer"), |
| 257 | sourceId: SourceIdSchema.make("src_invalid_bearer"), | 263 | sourceId: SourceIdSchema.make("src_invalid_bearer"), |
| 258 | payload: { | 264 | payload: { |
| 259 | name: "Bad Bearer", | 265 | name: "Bad Bearer", |
| @@ -279,7 +285,7 @@ describe("source-definitions", () => { · 19 unmodified lines | |||
| 279 | 285 | ||
| 280 | const invalidRefresh = yield* Effect.flip( | 286 | const invalidRefresh = yield* Effect.flip( |
| 281 | createSourceFromPayload({ | 287 | createSourceFromPayload({ |
| 282 | workspaceId: WorkspaceIdSchema.make("ws_invalid_refresh"), | 288 | scopeId: ScopeIdSchema.make("ws_invalid_refresh"), |
| 283 | sourceId: SourceIdSchema.make("src_invalid_refresh"), | 289 | sourceId: SourceIdSchema.make("src_invalid_refresh"), |
| 284 | payload: { | 290 | payload: { |
| 285 | name: "Bad OAuth", | 291 | name: "Bad OAuth", |
| @@ -313,7 +319,7 @@ describe("source-definitions", () => { · 27 unmodified lines | |||
| 313 | Effect.gen(function* () { | 319 | Effect.gen(function* () { |
| 314 | const invalidMcp = yield* Effect.flip( | 320 | const invalidMcp = yield* Effect.flip( |
| 315 | createSourceFromPayload({ | 321 | createSourceFromPayload({ |
| 316 | workspaceId: WorkspaceIdSchema.make("ws_invalid_mcp"), | 322 | scopeId: ScopeIdSchema.make("ws_invalid_mcp"), |
| 317 | sourceId: SourceIdSchema.make("src_invalid_mcp"), | 323 | sourceId: SourceIdSchema.make("src_invalid_mcp"), |
| 318 | payload: { | 324 | payload: { |
| 319 | name: "MCP", | 325 | name: "MCP", |
| @@ -332,7 +338,7 @@ describe("source-definitions", () => { · 12 unmodified lines | |||
| 332 | 338 | ||
| 333 | const invalidOpenApiSpec = yield* Effect.flip( | 339 | const invalidOpenApiSpec = yield* Effect.flip( |
| 334 | createSourceFromPayload({ | 340 | createSourceFromPayload({ |
| 335 | workspaceId: WorkspaceIdSchema.make("ws_invalid_openapi_spec"), | 341 | scopeId: ScopeIdSchema.make("ws_invalid_openapi_spec"), |
| 336 | sourceId: SourceIdSchema.make("src_invalid_openapi_spec"), | 342 | sourceId: SourceIdSchema.make("src_invalid_openapi_spec"), |
| 337 | payload: { | 343 | payload: { |
| 338 | name: "OpenAPI", | 344 | name: "OpenAPI", |
| @@ -349,7 +355,7 @@ describe("source-definitions", () => { · 10 unmodified lines | |||
| 349 | 355 | ||
| 350 | const invalidOpenApiTransport = yield* Effect.flip( | 356 | const invalidOpenApiTransport = yield* Effect.flip( |
| 351 | createSourceFromPayload({ | 357 | createSourceFromPayload({ |
| 352 | workspaceId: WorkspaceIdSchema.make("ws_invalid_openapi_transport"), | 358 | scopeId: ScopeIdSchema.make("ws_invalid_openapi_transport"), |
| 353 | sourceId: SourceIdSchema.make("src_invalid_openapi_transport"), | 359 | sourceId: SourceIdSchema.make("src_invalid_openapi_transport"), |
| 354 | payload: { | 360 | payload: { |
| 355 | name: "OpenAPI", | 361 | name: "OpenAPI", |
| @@ -369,7 +375,7 @@ describe("source-definitions", () => { · 13 unmodified lines | |||
| 369 | 375 | ||
| 370 | const invalidGraphql = yield* Effect.flip( | 376 | const invalidGraphql = yield* Effect.flip( |
| 371 | createSourceFromPayload({ | 377 | createSourceFromPayload({ |
| 372 | workspaceId: WorkspaceIdSchema.make("ws_invalid_graphql"), | 378 | scopeId: ScopeIdSchema.make("ws_invalid_graphql"), |
| 373 | sourceId: SourceIdSchema.make("src_invalid_graphql"), | 379 | sourceId: SourceIdSchema.make("src_invalid_graphql"), |
| 374 | payload: { | 380 | payload: { |
| 375 | name: "GraphQL", | 381 | name: "GraphQL", |
| @@ -388,7 +394,7 @@ describe("source-definitions", () => { · 12 unmodified lines | |||
| 388 | 394 | ||
| 389 | const invalidInternal = yield* Effect.flip( | 395 | const invalidInternal = yield* Effect.flip( |
| 390 | createSourceFromPayload({ | 396 | createSourceFromPayload({ |
| 391 | workspaceId: WorkspaceIdSchema.make("ws_invalid_internal"), | 397 | scopeId: ScopeIdSchema.make("ws_invalid_internal"), |
| 392 | sourceId: SourceIdSchema.make("src_invalid_internal"), | 398 | sourceId: SourceIdSchema.make("src_invalid_internal"), |
| 393 | payload: { | 399 | payload: { |
| 394 | name: "Internal", | 400 | name: "Internal", |
| @@ -1,11 +1,13 @@ | |||
| 1 | import { sha256Hex } from "@executor/codemode-core"; | 1 | import { |
| 2 | sha256Hex, | ||
| 3 | } from "@executor/codemode-core"; | ||
| 2 | 4 | ||
| 3 | import type { | 5 | import type { |
| 4 | CreateSourcePayload, | 6 | CreateSourcePayload, |
| 5 | UpdateSourcePayload, | 7 | UpdateSourcePayload, |
| 6 | } from "../../sources/contracts"; | 8 | } from "../../sources/contracts"; |
| 7 | import type { | 9 | import type { |
| 8 | AccountId, | 10 | ScopeId, |
| 9 | AuthArtifact, | 11 | AuthArtifact, |
| 10 | Source, | 12 | Source, |
| 11 | SourceAuth, | 13 | SourceAuth, |
| @@ -17,7 +19,6 @@ import type { · 5 unmodified lines | |||
| 17 | StoredSourceRecord, | 19 | StoredSourceRecord, |
| 18 | StoredSourceCatalogRecord, | 20 | StoredSourceCatalogRecord, |
| 19 | StoredSourceCatalogRevisionRecord, | 21 | StoredSourceCatalogRevisionRecord, |
| 20 | WorkspaceId, | ||
| 21 | } from "#schema"; | 22 | } from "#schema"; |
| 22 | import { | 23 | import { |
| 23 | AuthArtifactIdSchema, | 24 | AuthArtifactIdSchema, |
| @@ -27,12 +28,17 @@ import { · 3 unmodified lines | |||
| 27 | } from "#schema"; | 28 | } from "#schema"; |
| 28 | import * as Effect from "effect/Effect"; | 29 | import * as Effect from "effect/Effect"; |
| 29 | 30 | ||
| 30 | import { getSourceAdapter, getSourceAdapterForSource } from "./source-adapters"; | 31 | import { |
| 32 | getSourceAdapter, | ||
| 33 | getSourceAdapterForSource, | ||
| 34 | } from "./source-adapters"; | ||
| 31 | import { | 35 | import { |
| 32 | authArtifactFromSourceAuth, | 36 | authArtifactFromSourceAuth, |
| 33 | sourceAuthFromAuthArtifact, | 37 | sourceAuthFromAuthArtifact, |
| 34 | } from "../auth/auth-artifacts"; | 38 | } from "../auth/auth-artifacts"; |
| 35 | import { runtimeEffectError } from "../effect-errors"; | 39 | import { |
| 40 | runtimeEffectError, | ||
| 41 | } from "../effect-errors"; | ||
| 36 | 42 | ||
| 37 | const trimOrNull = (value: string | null | undefined): string | null => { | 43 | const trimOrNull = (value: string | null | undefined): string | null => { |
| 38 | if (value === null || value === undefined) { | 44 | if (value === null || value === undefined) { |
| @@ -277,7 +283,7 @@ const validateSourceByKind = (source: Source): Effect.Effect<Source, Error, neve · 238 unmodified lines | |||
| 277 | ); | 283 | ); |
| 278 | 284 | ||
| 279 | export const createSourceFromPayload = (input: { | 285 | export const createSourceFromPayload = (input: { |
| 280 | workspaceId: WorkspaceId; | 286 | scopeId: ScopeId; |
| 281 | sourceId: Source["id"]; | 287 | sourceId: Source["id"]; |
| 282 | payload: CreateSourcePayload; | 288 | payload: CreateSourcePayload; |
| 283 | now: number; | 289 | now: number; |
| @@ -292,7 +298,7 @@ export const createSourceFromPayload = (input: { · 8 unmodified lines | |||
| 292 | 298 | ||
| 293 | return yield* validateSourceByKind({ | 299 | return yield* validateSourceByKind({ |
| 294 | id: input.sourceId, | 300 | id: input.sourceId, |
| 295 | workspaceId: input.workspaceId, | 301 | scopeId: input.scopeId, |
| 296 | name: input.payload.name.trim(), | 302 | name: input.payload.name.trim(), |
| 297 | kind: input.payload.kind, | 303 | kind: input.payload.kind, |
| 298 | endpoint: input.payload.endpoint.trim(), | 304 | endpoint: input.payload.endpoint.trim(), |
| @@ -370,7 +376,7 @@ export const createSourceCatalogRecord = (input: { · 71 unmodified lines | |||
| 370 | providerKey: sourceCatalogProviderKeyFromSource(input.source), | 376 | providerKey: sourceCatalogProviderKeyFromSource(input.source), |
| 371 | name: input.source.name, | 377 | name: input.source.name, |
| 372 | summary: null, | 378 | summary: null, |
| 373 | visibility: "workspace", | 379 | visibility: "scope", |
| 374 | latestRevisionId: input.latestRevisionId, | 380 | latestRevisionId: input.latestRevisionId, |
| 375 | createdAt: input.source.createdAt, | 381 | createdAt: input.source.createdAt, |
| 376 | updatedAt: input.source.updatedAt, | 382 | updatedAt: input.source.updatedAt, |
| @@ -402,7 +408,7 @@ export const splitSourceForStorage = (input: { · 25 unmodified lines | |||
| 402 | source: Source; | 408 | source: Source; |
| 403 | catalogId: SourceCatalogId; | 409 | catalogId: SourceCatalogId; |
| 404 | catalogRevisionId: SourceCatalogRevisionId; | 410 | catalogRevisionId: SourceCatalogRevisionId; |
| 405 | actorAccountId?: AccountId | null; | 411 | actorScopeId?: ScopeId | null; |
| 406 | existingRuntimeAuthArtifactId?: AuthArtifact["id"] | null; | 412 | existingRuntimeAuthArtifactId?: AuthArtifact["id"] | null; |
| 407 | existingImportAuthArtifactId?: AuthArtifact["id"] | null; | 413 | existingImportAuthArtifactId?: AuthArtifact["id"] | null; |
| 408 | }): { | 414 | }): { |
| @@ -412,7 +418,7 @@ export const splitSourceForStorage = (input: { · 3 unmodified lines | |||
| 412 | } => { | 418 | } => { |
| 413 | const sourceRecord: StoredSourceRecord = { | 419 | const sourceRecord: StoredSourceRecord = { |
| 414 | id: input.source.id, | 420 | id: input.source.id, |
| 415 | workspaceId: input.source.workspaceId, | 421 | scopeId: input.source.scopeId, |
| 416 | catalogId: input.catalogId, | 422 | catalogId: input.catalogId, |
| 417 | catalogRevisionId: input.catalogRevisionId, | 423 | catalogRevisionId: input.catalogRevisionId, |
| 418 | name: input.source.name, | 424 | name: input.source.name, |
| @@ -435,7 +441,7 @@ export const splitSourceForStorage = (input: { · 16 unmodified lines | |||
| 435 | source: input.source, | 441 | source: input.source, |
| 436 | auth: input.source.auth, | 442 | auth: input.source.auth, |
| 437 | slot: "runtime", | 443 | slot: "runtime", |
| 438 | actorAccountId: input.actorAccountId, | 444 | actorScopeId: input.actorScopeId, |
| 439 | existingAuthArtifactId: input.existingRuntimeAuthArtifactId | 445 | existingAuthArtifactId: input.existingRuntimeAuthArtifactId |
| 440 | ?? AuthArtifactIdSchema.make(`auth_art_${crypto.randomUUID()}`), | 446 | ?? AuthArtifactIdSchema.make(`auth_art_${crypto.randomUUID()}`), |
| 441 | }), | 447 | }), |
| @@ -444,7 +450,7 @@ export const splitSourceForStorage = (input: { · 2 unmodified lines | |||
| 444 | source: input.source, | 450 | source: input.source, |
| 445 | auth: input.source.importAuth, | 451 | auth: input.source.importAuth, |
| 446 | slot: "import", | 452 | slot: "import", |
| 447 | actorAccountId: input.actorAccountId, | 453 | actorScopeId: input.actorScopeId, |
| 448 | existingAuthArtifactId: input.existingImportAuthArtifactId | 454 | existingAuthArtifactId: input.existingImportAuthArtifactId |
| 449 | ?? AuthArtifactIdSchema.make(`auth_art_${crypto.randomUUID()}`), | 455 | ?? AuthArtifactIdSchema.make(`auth_art_${crypto.randomUUID()}`), |
| 450 | }) | 456 | }) |
| @@ -466,7 +472,7 @@ export const projectSourceFromStorage = (input: { · 15 unmodified lines | |||
| 466 | 472 | ||
| 467 | return { | 473 | return { |
| 468 | id: input.sourceRecord.id, | 474 | id: input.sourceRecord.id, |
| 469 | workspaceId: input.sourceRecord.workspaceId, | 475 | scopeId: input.sourceRecord.scopeId, |
| 470 | name: input.sourceRecord.name, | 476 | name: input.sourceRecord.name, |
| 471 | kind: input.sourceRecord.kind, | 477 | kind: input.sourceRecord.kind, |
| 472 | endpoint: input.sourceRecord.endpoint, | 478 | endpoint: input.sourceRecord.endpoint, |
| @@ -507,7 +513,7 @@ export const projectSourcesFromStorage = (input: { · 34 unmodified lines | |||
| 507 | import: null, | 513 | import: null, |
| 508 | }; | 514 | }; |
| 509 | const current = authArtifact.slot === "runtime" ? existing.runtime : existing.import; | 515 | const current = authArtifact.slot === "runtime" ? existing.runtime : existing.import; |
| 510 | if (current === null || (current.actorAccountId === null && authArtifact.actorAccountId !== null)) { | 516 | if (current === null || (current.actorScopeId === null && authArtifact.actorScopeId !== null)) { |
| 511 | authArtifactsBySourceId.set(authArtifact.sourceId, { | 517 | authArtifactsBySourceId.set(authArtifact.sourceId, { |
| 512 | ...existing, | 518 | ...existing, |
| 513 | [authArtifact.slot]: authArtifact, | 519 | [authArtifact.slot]: authArtifact, |
| @@ -4,10 +4,16 @@ import { · 3 unmodified lines | |||
| 4 | type ServerResponse, | 4 | type ServerResponse, |
| 5 | } from "node:http"; | 5 | } from "node:http"; |
| 6 | 6 | ||
| 7 | import { describe, expect, it } from "@effect/vitest"; | 7 | import { |
| 8 | describe, | ||
| 9 | expect, | ||
| 10 | it, | ||
| 11 | } from "@effect/vitest"; | ||
| 8 | import * as Effect from "effect/Effect"; | 12 | import * as Effect from "effect/Effect"; |
| 9 | 13 | ||
| 10 | import { discoverSource } from "./source-discovery"; | 14 | import { |
| 15 | discoverSource, | ||
| 16 | } from "./source-discovery"; | ||
| 11 | 17 | ||
| 12 | type TestServer = { | 18 | type TestServer = { |
| 13 | url: string; | 19 | url: string; |
| @@ -1,8 +1,16 @@ | |||
| 1 | import { describe, expect, it } from "@effect/vitest"; | 1 | import { |
| 2 | describe, | ||
| 3 | expect, | ||
| 4 | it, | ||
| 5 | } from "@effect/vitest"; | ||
| 2 | import * as Effect from "effect/Effect"; | 6 | import * as Effect from "effect/Effect"; |
| 3 | 7 | ||
| 4 | import type { LoadedSourceCatalogTool } from "../catalog/source/runtime"; | 8 | import type { |
| 5 | import { inspectionToolDetailFromTool } from "./source-inspection"; | 9 | LoadedSourceCatalogTool, |
| 10 | } from "../catalog/source/runtime"; | ||
| 11 | import { | ||
| 12 | inspectionToolDetailFromTool, | ||
| 13 | } from "./source-inspection"; | ||
| 6 | 14 | ||
| 7 | describe("source inspection", () => { | 15 | describe("source inspection", () => { |
| 8 | it.effect("keeps the shared TypeScript contract first-class on tool detail", () => | 16 | it.effect("keeps the shared TypeScript contract first-class on tool detail", () => |
| @@ -1,17 +1,27 @@ | |||
| 1 | import { describe, expect, it } from "@effect/vitest"; | 1 | import { |
| 2 | describe, | ||
| 3 | expect, | ||
| 4 | it, | ||
| 5 | } from "@effect/vitest"; | ||
| 2 | import * as Effect from "effect/Effect"; | 6 | import * as Effect from "effect/Effect"; |
| 3 | 7 | ||
| 4 | import { | 8 | import { |
| 5 | SourceIdSchema, | 9 | SourceIdSchema, |
| 6 | WorkspaceIdSchema, | 10 | ScopeIdSchema, |
| 7 | type Source, | 11 | type Source, |
| 8 | } from "#schema"; | 12 | } from "#schema"; |
| 9 | 13 | ||
| 10 | import type { LoadedLocalExecutorConfig } from "../workspace-config"; | 14 | import type { |
| 11 | import { buildLocalSourceRecord } from "./source-store"; | 15 | LoadedLocalExecutorConfig, |
| 12 | import type { LocalWorkspaceState } from "../workspace-state"; | 16 | } from "../scope-config"; |
| 17 | import { | ||
| 18 | buildLocalSourceRecord, | ||
| 19 | } from "./source-store"; | ||
| 20 | import type { | ||
| 21 | LocalScopeState, | ||
| 22 | } from "../scope-state"; | ||
| 13 | 23 | ||
| 14 | const workspaceId = WorkspaceIdSchema.make("ws_source_store"); | 24 | const scopeId = ScopeIdSchema.make("ws_source_store"); |
| 15 | const sourceId = SourceIdSchema.make("linear"); | 25 | const sourceId = SourceIdSchema.make("linear"); |
| 16 | 26 | ||
| 17 | const loadedConfig: LoadedLocalExecutorConfig = { | 27 | const loadedConfig: LoadedLocalExecutorConfig = { |
| @@ -36,7 +46,7 @@ const loadedConfig: LoadedLocalExecutorConfig = { · 18 unmodified lines | |||
| 36 | projectConfigPath: "/tmp/project-config.jsonc", | 46 | projectConfigPath: "/tmp/project-config.jsonc", |
| 37 | }; | 47 | }; |
| 38 | 48 | ||
| 39 | const workspaceState: LocalWorkspaceState = { | 49 | const scopeState: LocalScopeState = { |
| 40 | version: 1, | 50 | version: 1, |
| 41 | sources: { | 51 | sources: { |
| 42 | [sourceId]: { | 52 | [sourceId]: { |
| @@ -54,16 +64,16 @@ describe("source-store", () => { · 11 unmodified lines | |||
| 54 | it.effect("projects configured sources without reading local artifacts", () => | 64 | it.effect("projects configured sources without reading local artifacts", () => |
| 55 | Effect.gen(function* () { | 65 | Effect.gen(function* () { |
| 56 | const result = yield* buildLocalSourceRecord({ | 66 | const result = yield* buildLocalSourceRecord({ |
| 57 | workspaceId, | 67 | scopeId, |
| 58 | loadedConfig, | 68 | loadedConfig, |
| 59 | workspaceState, | 69 | scopeState, |
| 60 | sourceId, | 70 | sourceId, |
| 61 | authArtifacts: [], | 71 | authArtifacts: [], |
| 62 | }); | 72 | }); |
| 63 | 73 | ||
| 64 | expect(result.source).toEqual({ | 74 | expect(result.source).toEqual({ |
| 65 | id: sourceId, | 75 | id: sourceId, |
| 66 | workspaceId, | 76 | scopeId, |
| 67 | name: "Linear GraphQL", | 77 | name: "Linear GraphQL", |
| 68 | kind: "graphql", | 78 | kind: "graphql", |
| 69 | endpoint: "https://api.linear.app/graphql", | 79 | endpoint: "https://api.linear.app/graphql", |
| @@ -1,22 +1,30 @@ | |||
| 1 | import type { | 1 | import type { |
| 2 | AccountId, | 2 | ScopeId, |
| 3 | Source, | 3 | Source, |
| 4 | WorkspaceId, | ||
| 5 | } from "#schema"; | 4 | } from "#schema"; |
| 6 | import * as Context from "effect/Context"; | 5 | import * as Context from "effect/Context"; |
| 7 | import * as Effect from "effect/Effect"; | 6 | import * as Effect from "effect/Effect"; |
| 8 | import * as Layer from "effect/Layer"; | 7 | import * as Layer from "effect/Layer"; |
| 9 | 8 | ||
| 10 | import { SourceTypeDeclarationsRefresherService } from "../catalog/source/type-declarations"; | 9 | import { |
| 10 | SourceTypeDeclarationsRefresherService, | ||
| 11 | } from "../catalog/source/type-declarations"; | ||
| 11 | import { | 12 | import { |
| 12 | SourceArtifactStore, | 13 | SourceArtifactStore, |
| 13 | type WorkspaceStorageServices, | 14 | type ScopeStorageServices, |
| 14 | WorkspaceConfigStore, | 15 | ScopeConfigStore, |
| 15 | WorkspaceStateStore, | 16 | ScopeStateStore, |
| 16 | } from "../workspace/storage"; | 17 | } from "../scope/storage"; |
| 17 | import { SecretMaterialDeleterService } from "../workspace/secret-material-providers"; | 18 | import { |
| 18 | import { RuntimeLocalWorkspaceService } from "../workspace/runtime-context"; | 19 | SecretMaterialDeleterService, |
| 19 | import { ExecutorStateStore, type ExecutorStateStoreShape } from "../executor-state-store"; | 20 | } from "../scope/secret-material-providers"; |
| 21 | import { | ||
| 22 | RuntimeLocalScopeService, | ||
| 23 | } from "../scope/runtime-context"; | ||
| 24 | import { | ||
| 25 | ExecutorStateStore, | ||
| 26 | type ExecutorStateStoreShape, | ||
| 27 | } from "../executor-state-store"; | ||
| 20 | import { | 28 | import { |
| 21 | loadRuntimeSourceStoreDeps, | 29 | loadRuntimeSourceStoreDeps, |
| 22 | type RuntimeSourceStoreDeps, | 30 | type RuntimeSourceStoreDeps, |
| @@ -35,95 +43,95 @@ import { · 12 unmodified lines | |||
| 35 | export { buildLocalSourceRecord } from "./source-store/records"; | 43 | export { buildLocalSourceRecord } from "./source-store/records"; |
| 36 | 44 | ||
| 37 | type RuntimeSourceStoreShape = { | 45 | type RuntimeSourceStoreShape = { |
| 38 | loadSourcesInWorkspace: ( | 46 | loadSourcesInScope: ( |
| 39 | workspaceId: WorkspaceId, | 47 | scopeId: ScopeId, |
| 40 | options?: { actorAccountId?: AccountId | null }, | 48 | options?: { actorScopeId?: ScopeId | null }, |
| 41 | ) => ReturnType<typeof loadSourcesInWorkspaceWithDeps>; | 49 | ) => ReturnType<typeof loadSourcesInWorkspaceWithDeps>; |
| 42 | listLinkedSecretSourcesInWorkspace: ( | 50 | listLinkedSecretSourcesInScope: ( |
| 43 | workspaceId: WorkspaceId, | 51 | scopeId: ScopeId, |
| 44 | options?: { actorAccountId?: AccountId | null }, | 52 | options?: { actorScopeId?: ScopeId | null }, |
| 45 | ) => ReturnType<typeof listLinkedSecretSourcesInWorkspaceWithDeps>; | 53 | ) => ReturnType<typeof listLinkedSecretSourcesInWorkspaceWithDeps>; |
| 46 | loadSourceById: (input: { | 54 | loadSourceById: (input: { |
| 47 | workspaceId: WorkspaceId; | 55 | scopeId: ScopeId; |
| 48 | sourceId: Source["id"]; | 56 | sourceId: Source["id"]; |
| 49 | actorAccountId?: AccountId | null; | 57 | actorScopeId?: ScopeId | null; |
| 50 | }) => ReturnType<typeof loadSourceByIdWithDeps>; | 58 | }) => ReturnType<typeof loadSourceByIdWithDeps>; |
| 51 | removeSourceById: (input: { | 59 | removeSourceById: (input: { |
| 52 | workspaceId: WorkspaceId; | 60 | scopeId: ScopeId; |
| 53 | sourceId: Source["id"]; | 61 | sourceId: Source["id"]; |
| 54 | }) => ReturnType<typeof removeSourceByIdWithDeps>; | 62 | }) => ReturnType<typeof removeSourceByIdWithDeps>; |
| 55 | persistSource: ( | 63 | persistSource: ( |
| 56 | source: Source, | 64 | source: Source, |
| 57 | options?: { actorAccountId?: AccountId | null }, | 65 | options?: { actorScopeId?: ScopeId | null }, |
| 58 | ) => ReturnType<typeof persistSourceWithDeps>; | 66 | ) => ReturnType<typeof persistSourceWithDeps>; |
| 59 | }; | 67 | }; |
| 60 | 68 | ||
| 61 | export type RuntimeSourceStore = RuntimeSourceStoreShape; | 69 | export type RuntimeSourceStore = RuntimeSourceStoreShape; |
| 62 | 70 | ||
| 63 | export const loadSourcesInWorkspace = ( | 71 | export const loadSourcesInScope = ( |
| 64 | executorState: ExecutorStateStoreShape, | 72 | executorState: ExecutorStateStoreShape, |
| 65 | workspaceId: WorkspaceId, | 73 | scopeId: ScopeId, |
| 66 | options: { | 74 | options: { |
| 67 | actorAccountId?: AccountId | null; | 75 | actorScopeId?: ScopeId | null; |
| 68 | } = {}, | 76 | } = {}, |
| 69 | ): Effect.Effect< | 77 | ): Effect.Effect< |
| 70 | readonly Source[], | 78 | readonly Source[], |
| 71 | Error, | 79 | Error, |
| 72 | WorkspaceStorageServices | SourceTypeDeclarationsRefresherService | 80 | ScopeStorageServices | SourceTypeDeclarationsRefresherService |
| 73 | > => | 81 | > => |
| 74 | Effect.flatMap( | 82 | Effect.flatMap( |
| 75 | loadRuntimeSourceStoreDeps(executorState, workspaceId), | 83 | loadRuntimeSourceStoreDeps(executorState, scopeId), |
| 76 | (deps) => loadSourcesInWorkspaceWithDeps(deps, workspaceId, options), | 84 | (deps) => loadSourcesInWorkspaceWithDeps(deps, scopeId, options), |
| 77 | ); | 85 | ); |
| 78 | 86 | ||
| 79 | export const listLinkedSecretSourcesInWorkspace = ( | 87 | export const listLinkedSecretSourcesInScope = ( |
| 80 | executorState: ExecutorStateStoreShape, | 88 | executorState: ExecutorStateStoreShape, |
| 81 | workspaceId: WorkspaceId, | 89 | scopeId: ScopeId, |
| 82 | options: { | 90 | options: { |
| 83 | actorAccountId?: AccountId | null; | 91 | actorScopeId?: ScopeId | null; |
| 84 | } = {}, | 92 | } = {}, |
| 85 | ): Effect.Effect< | 93 | ): Effect.Effect< |
| 86 | Map<string, Array<{ sourceId: string; sourceName: string }>>, | 94 | Map<string, Array<{ sourceId: string; sourceName: string }>>, |
| 87 | Error, | 95 | Error, |
| 88 | WorkspaceStorageServices | SourceTypeDeclarationsRefresherService | 96 | ScopeStorageServices | SourceTypeDeclarationsRefresherService |
| 89 | > => | 97 | > => |
| 90 | Effect.flatMap( | 98 | Effect.flatMap( |
| 91 | loadRuntimeSourceStoreDeps(executorState, workspaceId), | 99 | loadRuntimeSourceStoreDeps(executorState, scopeId), |
| 92 | (deps) => listLinkedSecretSourcesInWorkspaceWithDeps(deps, workspaceId, options), | 100 | (deps) => listLinkedSecretSourcesInWorkspaceWithDeps(deps, scopeId, options), |
| 93 | ); | 101 | ); |
| 94 | 102 | ||
| 95 | export const loadSourceById = ( | 103 | export const loadSourceById = ( |
| 96 | executorState: ExecutorStateStoreShape, | 104 | executorState: ExecutorStateStoreShape, |
| 97 | input: { | 105 | input: { |
| 98 | workspaceId: WorkspaceId; | 106 | scopeId: ScopeId; |
| 99 | sourceId: Source["id"]; | 107 | sourceId: Source["id"]; |
| 100 | actorAccountId?: AccountId | null; | 108 | actorScopeId?: ScopeId | null; |
| 101 | }, | 109 | }, |
| 102 | ): Effect.Effect< | 110 | ): Effect.Effect< |
| 103 | Source, | 111 | Source, |
| 104 | Error, | 112 | Error, |
| 105 | WorkspaceStorageServices | SourceTypeDeclarationsRefresherService | 113 | ScopeStorageServices | SourceTypeDeclarationsRefresherService |
| 106 | > => | 114 | > => |
| 107 | Effect.flatMap( | 115 | Effect.flatMap( |
| 108 | loadRuntimeSourceStoreDeps(executorState, input.workspaceId), | 116 | loadRuntimeSourceStoreDeps(executorState, input.scopeId), |
| 109 | (deps) => loadSourceByIdWithDeps(deps, input), | 117 | (deps) => loadSourceByIdWithDeps(deps, input), |
| 110 | ); | 118 | ); |
| 111 | 119 | ||
| 112 | export const removeSourceById = ( | 120 | export const removeSourceById = ( |
| 113 | executorState: ExecutorStateStoreShape, | 121 | executorState: ExecutorStateStoreShape, |
| 114 | input: { | 122 | input: { |
| 115 | workspaceId: WorkspaceId; | 123 | scopeId: ScopeId; |
| 116 | sourceId: Source["id"]; | 124 | sourceId: Source["id"]; |
| 117 | }, | 125 | }, |
| 118 | ): Effect.Effect< | 126 | ): Effect.Effect< |
| 119 | boolean, | 127 | boolean, |
| 120 | Error, | 128 | Error, |
| 121 | | WorkspaceStorageServices | 129 | | ScopeStorageServices |
| 122 | | SourceTypeDeclarationsRefresherService | 130 | | SourceTypeDeclarationsRefresherService |
| 123 | | SecretMaterialDeleterService | 131 | | SecretMaterialDeleterService |
| 124 | > => | 132 | > => |
| 125 | Effect.gen(function* () { | 133 | Effect.gen(function* () { |
| 126 | const deps = yield* loadRuntimeSourceStoreDeps(executorState, input.workspaceId); | 134 | const deps = yield* loadRuntimeSourceStoreDeps(executorState, input.scopeId); |
| 127 | const deleteSecretMaterial = yield* SecretMaterialDeleterService; | 135 | const deleteSecretMaterial = yield* SecretMaterialDeleterService; |
| 128 | return yield* removeSourceByIdWithDeps(deps, input, deleteSecretMaterial); | 136 | return yield* removeSourceByIdWithDeps(deps, input, deleteSecretMaterial); |
| 129 | }); | 137 | }); |
| @@ -132,17 +140,17 @@ export const persistSource = ( · 2 unmodified lines | |||
| 132 | executorState: ExecutorStateStoreShape, | 140 | executorState: ExecutorStateStoreShape, |
| 133 | source: Source, | 141 | source: Source, |
| 134 | options: { | 142 | options: { |
| 135 | actorAccountId?: AccountId | null; | 143 | actorScopeId?: ScopeId | null; |
| 136 | } = {}, | 144 | } = {}, |
| 137 | ): Effect.Effect< | 145 | ): Effect.Effect< |
| 138 | Source, | 146 | Source, |
| 139 | Error, | 147 | Error, |
| 140 | | WorkspaceStorageServices | 148 | | ScopeStorageServices |
| 141 | | SourceTypeDeclarationsRefresherService | 149 | | SourceTypeDeclarationsRefresherService |
| 142 | | SecretMaterialDeleterService | 150 | | SecretMaterialDeleterService |
| 143 | > => | 151 | > => |
| 144 | Effect.gen(function* () { | 152 | Effect.gen(function* () { |
| 145 | const deps = yield* loadRuntimeSourceStoreDeps(executorState, source.workspaceId); | 153 | const deps = yield* loadRuntimeSourceStoreDeps(executorState, source.scopeId); |
| 146 | const deleteSecretMaterial = yield* SecretMaterialDeleterService; | 154 | const deleteSecretMaterial = yield* SecretMaterialDeleterService; |
| 147 | return yield* persistSourceWithDeps(deps, source, options, deleteSecretMaterial); | 155 | return yield* persistSourceWithDeps(deps, source, options, deleteSecretMaterial); |
| 148 | }); | 156 | }); |
| @@ -155,9 +163,9 @@ export const RuntimeSourceStoreLive = Layer.effect( · 6 unmodified lines | |||
| 155 | RuntimeSourceStoreService, | 163 | RuntimeSourceStoreService, |
| 156 | Effect.gen(function* () { | 164 | Effect.gen(function* () { |
| 157 | const executorState = yield* ExecutorStateStore; | 165 | const executorState = yield* ExecutorStateStore; |
| 158 | const runtimeLocalWorkspace = yield* RuntimeLocalWorkspaceService; | 166 | const runtimeLocalScope = yield* RuntimeLocalScopeService; |
| 159 | const workspaceConfigStore = yield* WorkspaceConfigStore; | 167 | const scopeConfigStore = yield* ScopeConfigStore; |
| 160 | const workspaceStateStore = yield* WorkspaceStateStore; | 168 | const scopeStateStore = yield* ScopeStateStore; |
| 161 | const sourceArtifactStore = yield* SourceArtifactStore; | 169 | const sourceArtifactStore = yield* SourceArtifactStore; |
| 162 | const sourceTypeDeclarationsRefresher = | 170 | const sourceTypeDeclarationsRefresher = |
| 163 | yield* SourceTypeDeclarationsRefresherService; | 171 | yield* SourceTypeDeclarationsRefresherService; |
| @@ -165,18 +173,18 @@ export const RuntimeSourceStoreLive = Layer.effect( · 1 unmodified line | |||
| 165 | 173 | ||
| 166 | const deps: RuntimeSourceStoreDeps = { | 174 | const deps: RuntimeSourceStoreDeps = { |
| 167 | executorState, | 175 | executorState, |
| 168 | runtimeLocalWorkspace, | 176 | runtimeLocalScope, |
| 169 | workspaceConfigStore, | 177 | scopeConfigStore, |
| 170 | workspaceStateStore, | 178 | scopeStateStore, |
| 171 | sourceArtifactStore, | 179 | sourceArtifactStore, |
| 172 | sourceTypeDeclarationsRefresher, | 180 | sourceTypeDeclarationsRefresher, |
| 173 | }; | 181 | }; |
| 174 | 182 | ||
| 175 | return RuntimeSourceStoreService.of({ | 183 | return RuntimeSourceStoreService.of({ |
| 176 | loadSourcesInWorkspace: (workspaceId, options = {}) => | 184 | loadSourcesInScope: (scopeId, options = {}) => |
| 177 | loadSourcesInWorkspaceWithDeps(deps, workspaceId, options), | 185 | loadSourcesInWorkspaceWithDeps(deps, scopeId, options), |
| 178 | listLinkedSecretSourcesInWorkspace: (workspaceId, options = {}) => | 186 | listLinkedSecretSourcesInScope: (scopeId, options = {}) => |
| 179 | listLinkedSecretSourcesInWorkspaceWithDeps(deps, workspaceId, options), | 187 | listLinkedSecretSourcesInWorkspaceWithDeps(deps, scopeId, options), |
| 180 | loadSourceById: (input) => | 188 | loadSourceById: (input) => |
| 181 | loadSourceByIdWithDeps(deps, input), | 189 | loadSourceByIdWithDeps(deps, input), |
| 182 | removeSourceById: (input) => | 190 | removeSourceById: (input) => |
| @@ -1,18 +1,27 @@ | |||
| 1 | import type { | 1 | import type { |
| 2 | AccountId, | 2 | ScopeId, |
| 3 | AuthArtifact, | 3 | AuthArtifact, |
| 4 | CredentialSlot, | 4 | CredentialSlot, |
| 5 | ProviderAuthGrant, | 5 | ProviderAuthGrant, |
| 6 | Source, | 6 | Source, |
| 7 | WorkspaceId, | ||
| 8 | } from "#schema"; | 7 | } from "#schema"; |
| 9 | import { decodeProviderGrantRefAuthArtifactConfig } from "#schema"; | 8 | import { |
| 9 | decodeProviderGrantRefAuthArtifactConfig, | ||
| 10 | } from "#schema"; | ||
| 10 | import * as Effect from "effect/Effect"; | 11 | import * as Effect from "effect/Effect"; |
| 11 | 12 | ||
| 12 | import { authArtifactSecretMaterialRefs } from "../../auth/auth-artifacts"; | 13 | import { |
| 13 | import { removeAuthLeaseAndSecrets } from "../../auth/auth-leases"; | 14 | authArtifactSecretMaterialRefs, |
| 14 | import type { DeleteSecretMaterial } from "../../workspace/secret-material-providers"; | 15 | } from "../../auth/auth-artifacts"; |
| 15 | import type { ExecutorStateStoreShape } from "../../executor-state-store"; | 16 | import { |
| 17 | removeAuthLeaseAndSecrets, | ||
| 18 | } from "../../auth/auth-leases"; | ||
| 19 | import type { | ||
| 20 | DeleteSecretMaterial, | ||
| 21 | } from "../../scope/secret-material-providers"; | ||
| 22 | import type { | ||
| 23 | ExecutorStateStoreShape, | ||
| 24 | } from "../../executor-state-store"; | ||
| 16 | 25 | ||
| 17 | const secretRefKey = (ref: { providerId: string; handle: string }): string => | 26 | const secretRefKey = (ref: { providerId: string; handle: string }): string => |
| 18 | `${ref.providerId}:${ref.handle}`; | 27 | `${ref.providerId}:${ref.handle}`; |
| @@ -60,52 +69,52 @@ export const providerGrantIdsFromArtifacts = ( · 41 unmodified lines | |||
| 60 | 69 | ||
| 61 | export const selectPreferredAuthArtifact = (input: { | 70 | export const selectPreferredAuthArtifact = (input: { |
| 62 | authArtifacts: ReadonlyArray<AuthArtifact>; | 71 | authArtifacts: ReadonlyArray<AuthArtifact>; |
| 63 | actorAccountId?: AccountId | null; | 72 | actorScopeId?: ScopeId | null; |
| 64 | slot: CredentialSlot; | 73 | slot: CredentialSlot; |
| 65 | }): AuthArtifact | null => { | 74 | }): AuthArtifact | null => { |
| 66 | const matchingSlot = input.authArtifacts.filter( | 75 | const matchingSlot = input.authArtifacts.filter( |
| 67 | (artifact) => artifact.slot === input.slot, | 76 | (artifact) => artifact.slot === input.slot, |
| 68 | ); | 77 | ); |
| 69 | 78 | ||
| 70 | if (input.actorAccountId !== undefined) { | 79 | if (input.actorScopeId !== undefined) { |
| 71 | const exact = matchingSlot.find( | 80 | const exact = matchingSlot.find( |
| 72 | (artifact) => artifact.actorAccountId === input.actorAccountId, | 81 | (artifact) => artifact.actorScopeId === input.actorScopeId, |
| 73 | ); | 82 | ); |
| 74 | if (exact) { | 83 | if (exact) { |
| 75 | return exact; | 84 | return exact; |
| 76 | } | 85 | } |
| 77 | } | 86 | } |
| 78 | 87 | ||
| 79 | return matchingSlot.find((artifact) => artifact.actorAccountId === null) ?? null; | 88 | return matchingSlot.find((artifact) => artifact.actorScopeId === null) ?? null; |
| 80 | }; | 89 | }; |
| 81 | 90 | ||
| 82 | export const selectExactAuthArtifact = (input: { | 91 | export const selectExactAuthArtifact = (input: { |
| 83 | authArtifacts: ReadonlyArray<AuthArtifact>; | 92 | authArtifacts: ReadonlyArray<AuthArtifact>; |
| 84 | actorAccountId?: AccountId | null; | 93 | actorScopeId?: ScopeId | null; |
| 85 | slot: CredentialSlot; | 94 | slot: CredentialSlot; |
| 86 | }): AuthArtifact | null => | 95 | }): AuthArtifact | null => |
| 87 | input.authArtifacts.find( | 96 | input.authArtifacts.find( |
| 88 | (artifact) => | 97 | (artifact) => |
| 89 | artifact.slot === input.slot && | 98 | artifact.slot === input.slot && |
| 90 | artifact.actorAccountId === (input.actorAccountId ?? null), | 99 | artifact.actorScopeId === (input.actorScopeId ?? null), |
| 91 | ) ?? null; | 100 | ) ?? null; |
| 92 | 101 | ||
| 93 | export const removeAuthArtifactsForSource = ( | 102 | export const removeAuthArtifactsForSource = ( |
| 94 | executorState: ExecutorStateStoreShape, | 103 | executorState: ExecutorStateStoreShape, |
| 95 | input: { | 104 | input: { |
| 96 | workspaceId: WorkspaceId; | 105 | scopeId: ScopeId; |
| 97 | sourceId: Source["id"]; | 106 | sourceId: Source["id"]; |
| 98 | }, | 107 | }, |
| 99 | deleteSecretMaterial: DeleteSecretMaterial, | 108 | deleteSecretMaterial: DeleteSecretMaterial, |
| 100 | ) => | 109 | ) => |
| 101 | Effect.gen(function* () { | 110 | Effect.gen(function* () { |
| 102 | const existingAuthArtifacts = yield* executorState.authArtifacts.listByWorkspaceAndSourceId({ | 111 | const existingAuthArtifacts = yield* executorState.authArtifacts.listByScopeAndSourceId({ |
| 103 | workspaceId: input.workspaceId, | 112 | scopeId: input.scopeId, |
| 104 | sourceId: input.sourceId, | 113 | sourceId: input.sourceId, |
| 105 | }); | 114 | }); |
| 106 | 115 | ||
| 107 | yield* executorState.authArtifacts.removeByWorkspaceAndSourceId({ | 116 | yield* executorState.authArtifacts.removeByScopeAndSourceId({ |
| 108 | workspaceId: input.workspaceId, | 117 | scopeId: input.scopeId, |
| 109 | sourceId: input.sourceId, | 118 | sourceId: input.sourceId, |
| 110 | }); | 119 | }); |
| 111 | 120 | ||
| @@ -4,16 +4,26 @@ import type { · 3 unmodified lines | |||
| 4 | Source, | 4 | Source, |
| 5 | SourceId, | 5 | SourceId, |
| 6 | } from "#schema"; | 6 | } from "#schema"; |
| 7 | import { SourceIdSchema } from "#schema"; | 7 | import { |
| 8 | SourceIdSchema, | ||
| 9 | } from "#schema"; | ||
| 8 | 10 | ||
| 9 | import type { LoadedLocalExecutorConfig } from "../../workspace-config"; | 11 | import type { |
| 10 | import { LocalUnsupportedSourceKindError } from "../../workspace-errors"; | 12 | LoadedLocalExecutorConfig, |
| 13 | } from "../../scope-config"; | ||
| 14 | import { | ||
| 15 | LocalUnsupportedSourceKindError, | ||
| 16 | } from "../../scope-errors"; | ||
| 11 | import { | 17 | import { |
| 12 | fromConfigSecretProviderId, | 18 | fromConfigSecretProviderId, |
| 13 | toConfigSecretProviderId, | 19 | toConfigSecretProviderId, |
| 14 | } from "../../workspace/config-secrets"; | 20 | } from "../../scope/config-secrets"; |
| 15 | import { getSourceAdapterForSource } from "../source-adapters"; | 21 | import { |
| 16 | import { slugify } from "../slug"; | 22 | getSourceAdapterForSource, |
| 23 | } from "../source-adapters"; | ||
| 24 | import { | ||
| 25 | slugify, | ||
| 26 | } from "../slug"; | ||
| 17 | 27 | ||
| 18 | export const trimOrNull = (value: string | null | undefined): string | null => { | 28 | export const trimOrNull = (value: string | null | undefined): string | null => { |
| 19 | if (value == null) { | 29 | if (value == null) { |
| @@ -1,112 +1,120 @@ | |||
| 1 | import type { AccountId, WorkspaceId } from "#schema"; | 1 | import type { |
| 2 | ScopeId, | ||
| 3 | } from "#schema"; | ||
| 2 | import * as Effect from "effect/Effect"; | 4 | import * as Effect from "effect/Effect"; |
| 3 | 5 | ||
| 4 | import type { LoadedLocalExecutorConfig } from "../../workspace-config"; | 6 | import type { |
| 7 | LoadedLocalExecutorConfig, | ||
| 8 | } from "../../scope-config"; | ||
| 5 | import { | 9 | import { |
| 6 | SourceTypeDeclarationsRefresherService, | 10 | SourceTypeDeclarationsRefresherService, |
| 7 | type SourceTypeDeclarationsRefresherShape, | 11 | type SourceTypeDeclarationsRefresherShape, |
| 8 | } from "../../catalog/source/type-declarations"; | 12 | } from "../../catalog/source/type-declarations"; |
| 9 | import { | 13 | import { |
| 10 | RuntimeLocalWorkspaceMismatchError, | 14 | RuntimeLocalScopeMismatchError, |
| 11 | RuntimeLocalWorkspaceUnavailableError, | 15 | RuntimeLocalScopeUnavailableError, |
| 12 | } from "../../workspace-errors"; | 16 | } from "../../scope-errors"; |
| 13 | import { | 17 | import { |
| 14 | requireRuntimeLocalWorkspace, | 18 | requireRuntimeLocalScope, |
| 15 | type RuntimeLocalWorkspaceState, | 19 | type RuntimeLocalScopeState, |
| 16 | } from "../../workspace/runtime-context"; | 20 | } from "../../scope/runtime-context"; |
| 17 | import type { | 21 | import type { |
| 18 | SourceArtifactStoreShape, | 22 | SourceArtifactStoreShape, |
| 19 | WorkspaceStorageServices, | 23 | ScopeStorageServices, |
| 20 | WorkspaceConfigStoreShape, | 24 | ScopeConfigStoreShape, |
| 21 | WorkspaceStateStoreShape, | 25 | ScopeStateStoreShape, |
| 22 | } from "../../workspace/storage"; | 26 | } from "../../scope/storage"; |
| 23 | import { | 27 | import { |
| 24 | SourceArtifactStore, | 28 | SourceArtifactStore, |
| 25 | WorkspaceConfigStore, | 29 | ScopeConfigStore, |
| 26 | WorkspaceStateStore, | 30 | ScopeStateStore, |
| 27 | } from "../../workspace/storage"; | 31 | } from "../../scope/storage"; |
| 28 | import type { LocalWorkspaceState } from "../../workspace-state"; | 32 | import type { |
| 29 | import type { ExecutorStateStoreShape } from "../../executor-state-store"; | 33 | LocalScopeState, |
| 34 | } from "../../scope-state"; | ||
| 35 | import type { | ||
| 36 | ExecutorStateStoreShape, | ||
| 37 | } from "../../executor-state-store"; | ||
| 30 | 38 | ||
| 31 | export type RuntimeSourceStoreDeps = { | 39 | export type RuntimeSourceStoreDeps = { |
| 32 | executorState: ExecutorStateStoreShape; | 40 | executorState: ExecutorStateStoreShape; |
| 33 | runtimeLocalWorkspace: RuntimeLocalWorkspaceState; | 41 | runtimeLocalScope: RuntimeLocalScopeState; |
| 34 | workspaceConfigStore: WorkspaceConfigStoreShape; | 42 | scopeConfigStore: ScopeConfigStoreShape; |
| 35 | workspaceStateStore: WorkspaceStateStoreShape; | 43 | scopeStateStore: ScopeStateStoreShape; |
| 36 | sourceArtifactStore: SourceArtifactStoreShape; | 44 | sourceArtifactStore: SourceArtifactStoreShape; |
| 37 | sourceTypeDeclarationsRefresher: SourceTypeDeclarationsRefresherShape; | 45 | sourceTypeDeclarationsRefresher: SourceTypeDeclarationsRefresherShape; |
| 38 | }; | 46 | }; |
| 39 | 47 | ||
| 40 | export type ResolvedSourceStoreWorkspace = { | 48 | export type ResolvedSourceStoreScope = { |
| 41 | installation: { | 49 | installation: { |
| 42 | workspaceId: WorkspaceId; | 50 | scopeId: ScopeId; |
| 43 | accountId: AccountId; | 51 | actorScopeId: ScopeId; |
| 44 | }; | 52 | }; |
| 45 | workspaceConfigStore: WorkspaceConfigStoreShape; | 53 | scopeConfigStore: ScopeConfigStoreShape; |
| 46 | workspaceStateStore: WorkspaceStateStoreShape; | 54 | scopeStateStore: ScopeStateStoreShape; |
| 47 | sourceArtifactStore: SourceArtifactStoreShape; | 55 | sourceArtifactStore: SourceArtifactStoreShape; |
| 48 | loadedConfig: LoadedLocalExecutorConfig; | 56 | loadedConfig: LoadedLocalExecutorConfig; |
| 49 | workspaceState: LocalWorkspaceState; | 57 | scopeState: LocalScopeState; |
| 50 | }; | 58 | }; |
| 51 | 59 | ||
| 52 | export type RuntimeSourceStoreServices = | 60 | export type RuntimeSourceStoreServices = |
| 53 | WorkspaceStorageServices | SourceTypeDeclarationsRefresherService; | 61 | ScopeStorageServices | SourceTypeDeclarationsRefresherService; |
| 54 | 62 | ||
| 55 | export const resolveRuntimeLocalWorkspaceFromDeps = ( | 63 | export const resolveRuntimeLocalScopeFromDeps = ( |
| 56 | deps: RuntimeSourceStoreDeps, | 64 | deps: RuntimeSourceStoreDeps, |
| 57 | workspaceId: WorkspaceId, | 65 | scopeId: ScopeId, |
| 58 | ): Effect.Effect< | 66 | ): Effect.Effect< |
| 59 | ResolvedSourceStoreWorkspace, | 67 | ResolvedSourceStoreScope, |
| 60 | | RuntimeLocalWorkspaceUnavailableError | 68 | | RuntimeLocalScopeUnavailableError |
| 61 | | RuntimeLocalWorkspaceMismatchError | 69 | | RuntimeLocalScopeMismatchError |
| 62 | | Error, | 70 | | Error, |
| 63 | never | 71 | never |
| 64 | > => | 72 | > => |
| 65 | Effect.gen(function* () { | 73 | Effect.gen(function* () { |
| 66 | if (deps.runtimeLocalWorkspace.installation.workspaceId !== workspaceId) { | 74 | if (deps.runtimeLocalScope.installation.scopeId !== scopeId) { |
| 67 | return yield* new RuntimeLocalWorkspaceMismatchError({ | 75 | return yield* new RuntimeLocalScopeMismatchError({ |
| 68 | message: `Runtime local workspace mismatch: expected ${workspaceId}, got ${deps.runtimeLocalWorkspace.installation.workspaceId}`, | 76 | message: `Runtime local scope mismatch: expected ${scopeId}, got ${deps.runtimeLocalScope.installation.scopeId}`, |
| 69 | requestedWorkspaceId: workspaceId, | 77 | requestedScopeId: scopeId, |
| 70 | activeWorkspaceId: deps.runtimeLocalWorkspace.installation.workspaceId, | 78 | activeScopeId: deps.runtimeLocalScope.installation.scopeId, |
| 71 | }); | 79 | }); |
| 72 | } | 80 | } |
| 73 | 81 | ||
| 74 | const loadedConfig = yield* deps.workspaceConfigStore.load(); | 82 | const loadedConfig = yield* deps.scopeConfigStore.load(); |
| 75 | const workspaceState = yield* deps.workspaceStateStore.load(); | 83 | const scopeState = yield* deps.scopeStateStore.load(); |
| 76 | 84 | ||
| 77 | return { | 85 | return { |
| 78 | installation: deps.runtimeLocalWorkspace.installation, | 86 | installation: deps.runtimeLocalScope.installation, |
| 79 | workspaceConfigStore: deps.workspaceConfigStore, | 87 | scopeConfigStore: deps.scopeConfigStore, |
| 80 | workspaceStateStore: deps.workspaceStateStore, | 88 | scopeStateStore: deps.scopeStateStore, |
| 81 | sourceArtifactStore: deps.sourceArtifactStore, | 89 | sourceArtifactStore: deps.sourceArtifactStore, |
| 82 | loadedConfig, | 90 | loadedConfig, |
| 83 | workspaceState, | 91 | scopeState, |
| 84 | }; | 92 | }; |
| 85 | }); | 93 | }); |
| 86 | 94 | ||
| 87 | export const loadRuntimeSourceStoreDeps = ( | 95 | export const loadRuntimeSourceStoreDeps = ( |
| 88 | executorState: ExecutorStateStoreShape, | 96 | executorState: ExecutorStateStoreShape, |
| 89 | workspaceId: WorkspaceId, | 97 | scopeId: ScopeId, |
| 90 | ): Effect.Effect< | 98 | ): Effect.Effect< |
| 91 | RuntimeSourceStoreDeps, | 99 | RuntimeSourceStoreDeps, |
| 92 | | RuntimeLocalWorkspaceUnavailableError | 100 | | RuntimeLocalScopeUnavailableError |
| 93 | | RuntimeLocalWorkspaceMismatchError | 101 | | RuntimeLocalScopeMismatchError |
| 94 | | Error, | 102 | | Error, |
| 95 | RuntimeSourceStoreServices | 103 | RuntimeSourceStoreServices |
| 96 | > => | 104 | > => |
| 97 | Effect.gen(function* () { | 105 | Effect.gen(function* () { |
| 98 | const runtimeLocalWorkspace = yield* requireRuntimeLocalWorkspace(workspaceId); | 106 | const runtimeLocalScope = yield* requireRuntimeLocalScope(scopeId); |
| 99 | const workspaceConfigStore = yield* WorkspaceConfigStore; | 107 | const scopeConfigStore = yield* ScopeConfigStore; |
| 100 | const workspaceStateStore = yield* WorkspaceStateStore; | 108 | const scopeStateStore = yield* ScopeStateStore; |
| 101 | const sourceArtifactStore = yield* SourceArtifactStore; | 109 | const sourceArtifactStore = yield* SourceArtifactStore; |
| 102 | const sourceTypeDeclarationsRefresher = | 110 | const sourceTypeDeclarationsRefresher = |
| 103 | yield* SourceTypeDeclarationsRefresherService; | 111 | yield* SourceTypeDeclarationsRefresherService; |
| 104 | 112 | ||
| 105 | return { | 113 | return { |
| 106 | executorState, | 114 | executorState, |
| 107 | runtimeLocalWorkspace, | 115 | runtimeLocalScope, |
| 108 | workspaceConfigStore, | 116 | scopeConfigStore, |
| 109 | workspaceStateStore, | 117 | scopeStateStore, |
| 110 | sourceArtifactStore, | 118 | sourceArtifactStore, |
| 111 | sourceTypeDeclarationsRefresher, | 119 | sourceTypeDeclarationsRefresher, |
| 112 | }; | 120 | }; |
| @@ -1,13 +1,22 @@ | |||
| 1 | import type { AccountId, Source, WorkspaceId } from "#schema"; | 1 | import type { |
| 2 | ScopeId, | ||
| 3 | Source, | ||
| 4 | } from "#schema"; | ||
| 2 | import * as Effect from "effect/Effect"; | 5 | import * as Effect from "effect/Effect"; |
| 3 | 6 | ||
| 4 | import { removeAuthLeaseAndSecrets } from "../../auth/auth-leases"; | 7 | import { |
| 8 | removeAuthLeaseAndSecrets, | ||
| 9 | } from "../../auth/auth-leases"; | ||
| 5 | import { | 10 | import { |
| 6 | clearProviderGrantOrphanedAt, | 11 | clearProviderGrantOrphanedAt, |
| 7 | markProviderGrantOrphanedIfUnused, | 12 | markProviderGrantOrphanedIfUnused, |
| 8 | } from "../../auth/provider-grant-lifecycle"; | 13 | } from "../../auth/provider-grant-lifecycle"; |
| 9 | import type { DeleteSecretMaterial } from "../../workspace/secret-material-providers"; | 14 | import type { |
| 10 | import type { LocalWorkspaceState } from "../../workspace-state"; | 15 | DeleteSecretMaterial, |
| 16 | } from "../../scope/secret-material-providers"; | ||
| 17 | import type { | ||
| 18 | LocalScopeState, | ||
| 19 | } from "../../scope-state"; | ||
| 11 | import { | 20 | import { |
| 12 | stableSourceCatalogId, | 21 | stableSourceCatalogId, |
| 13 | stableSourceCatalogRevisionId, | 22 | stableSourceCatalogRevisionId, |
| @@ -26,37 +35,37 @@ import { · 12 unmodified lines | |||
| 26 | } from "./config"; | 35 | } from "./config"; |
| 27 | import { | 36 | import { |
| 28 | type RuntimeSourceStoreDeps, | 37 | type RuntimeSourceStoreDeps, |
| 29 | resolveRuntimeLocalWorkspaceFromDeps, | 38 | resolveRuntimeLocalScopeFromDeps, |
| 30 | } from "./deps"; | 39 | } from "./deps"; |
| 31 | import { | 40 | import { |
| 32 | loadSourceByIdWithDeps, | 41 | loadSourceByIdWithDeps, |
| 33 | shouldRefreshWorkspaceDeclarationsAfterPersist, | 42 | shouldRefreshScopeDeclarationsAfterPersist, |
| 34 | syncWorkspaceSourceTypeDeclarationsWithDeps, | 43 | syncScopeSourceTypeDeclarationsWithDeps, |
| 35 | } from "./records"; | 44 | } from "./records"; |
| 36 | 45 | ||
| 37 | export const removeSourceByIdWithDeps = ( | 46 | export const removeSourceByIdWithDeps = ( |
| 38 | deps: RuntimeSourceStoreDeps, | 47 | deps: RuntimeSourceStoreDeps, |
| 39 | input: { | 48 | input: { |
| 40 | workspaceId: WorkspaceId; | 49 | scopeId: ScopeId; |
| 41 | sourceId: Source["id"]; | 50 | sourceId: Source["id"]; |
| 42 | }, | 51 | }, |
| 43 | deleteSecretMaterial: DeleteSecretMaterial, | 52 | deleteSecretMaterial: DeleteSecretMaterial, |
| 44 | ): Effect.Effect<boolean, Error, never> => | 53 | ): Effect.Effect<boolean, Error, never> => |
| 45 | Effect.gen(function* () { | 54 | Effect.gen(function* () { |
| 46 | const localWorkspace = yield* resolveRuntimeLocalWorkspaceFromDeps( | 55 | const localScope = yield* resolveRuntimeLocalScopeFromDeps( |
| 47 | deps, | 56 | deps, |
| 48 | input.workspaceId, | 57 | input.scopeId, |
| 49 | ); | 58 | ); |
| 50 | if (!localWorkspace.loadedConfig.config?.sources?.[input.sourceId]) { | 59 | if (!localScope.loadedConfig.config?.sources?.[input.sourceId]) { |
| 51 | return false; | 60 | return false; |
| 52 | } | 61 | } |
| 53 | 62 | ||
| 54 | const projectConfig = cloneJson(localWorkspace.loadedConfig.projectConfig ?? {}); | 63 | const projectConfig = cloneJson(localScope.loadedConfig.projectConfig ?? {}); |
| 55 | const sources = { | 64 | const sources = { |
| 56 | ...projectConfig.sources, | 65 | ...projectConfig.sources, |
| 57 | }; | 66 | }; |
| 58 | delete sources[input.sourceId]; | 67 | delete sources[input.sourceId]; |
| 59 | yield* localWorkspace.workspaceConfigStore.writeProject({ | 68 | yield* localScope.scopeConfigStore.writeProject({ |
| 60 | config: { | 69 | config: { |
| 61 | ...projectConfig, | 70 | ...projectConfig, |
| 62 | sources, | 71 | sources, |
| @@ -64,30 +73,30 @@ export const removeSourceByIdWithDeps = ( · 1 unmodified line | |||
| 64 | }); | 73 | }); |
| 65 | 74 | ||
| 66 | const { [input.sourceId]: _removedSource, ...remainingSources } = | 75 | const { [input.sourceId]: _removedSource, ...remainingSources } = |
| 67 | localWorkspace.workspaceState.sources; | 76 | localScope.scopeState.sources; |
| 68 | const workspaceState: LocalWorkspaceState = { | 77 | const scopeState: LocalScopeState = { |
| 69 | ...localWorkspace.workspaceState, | 78 | ...localScope.scopeState, |
| 70 | sources: remainingSources, | 79 | sources: remainingSources, |
| 71 | }; | 80 | }; |
| 72 | yield* localWorkspace.workspaceStateStore.write({ | 81 | yield* localScope.scopeStateStore.write({ |
| 73 | state: workspaceState, | 82 | state: scopeState, |
| 74 | }); | 83 | }); |
| 75 | yield* localWorkspace.sourceArtifactStore.remove({ | 84 | yield* localScope.sourceArtifactStore.remove({ |
| 76 | sourceId: input.sourceId, | 85 | sourceId: input.sourceId, |
| 77 | }); | 86 | }); |
| 78 | const existingAuthArtifacts = | 87 | const existingAuthArtifacts = |
| 79 | yield* deps.executorState.authArtifacts.listByWorkspaceAndSourceId({ | 88 | yield* deps.executorState.authArtifacts.listByScopeAndSourceId({ |
| 80 | workspaceId: input.workspaceId, | 89 | scopeId: input.scopeId, |
| 81 | sourceId: input.sourceId, | 90 | sourceId: input.sourceId, |
| 82 | }); | 91 | }); |
| 83 | const removedGrantIds = providerGrantIdsFromArtifacts(existingAuthArtifacts); | 92 | const removedGrantIds = providerGrantIdsFromArtifacts(existingAuthArtifacts); |
| 84 | 93 | ||
| 85 | yield* deps.executorState.sourceAuthSessions.removeByWorkspaceAndSourceId( | 94 | yield* deps.executorState.sourceAuthSessions.removeByScopeAndSourceId( |
| 86 | input.workspaceId, | 95 | input.scopeId, |
| 87 | input.sourceId, | 96 | input.sourceId, |
| 88 | ); | 97 | ); |
| 89 | yield* deps.executorState.sourceOauthClients.removeByWorkspaceAndSourceId({ | 98 | yield* deps.executorState.sourceOauthClients.removeByScopeAndSourceId({ |
| 90 | workspaceId: input.workspaceId, | 99 | scopeId: input.scopeId, |
| 91 | sourceId: input.sourceId, | 100 | sourceId: input.sourceId, |
| 92 | }); | 101 | }); |
| 93 | yield* removeAuthArtifactsForSource(deps.executorState, input, deleteSecretMaterial); | 102 | yield* removeAuthArtifactsForSource(deps.executorState, input, deleteSecretMaterial); |
| @@ -95,12 +104,12 @@ export const removeSourceByIdWithDeps = ( · 1 unmodified line | |||
| 95 | [...removedGrantIds], | 104 | [...removedGrantIds], |
| 96 | (grantId) => | 105 | (grantId) => |
| 97 | markProviderGrantOrphanedIfUnused(deps.executorState, { | 106 | markProviderGrantOrphanedIfUnused(deps.executorState, { |
| 98 | workspaceId: input.workspaceId, | 107 | scopeId: input.scopeId, |
| 99 | grantId, | 108 | grantId, |
| 100 | }), | 109 | }), |
| 101 | { discard: true }, | 110 | { discard: true }, |
| 102 | ); | 111 | ); |
| 103 | yield* syncWorkspaceSourceTypeDeclarationsWithDeps(deps, input.workspaceId); | 112 | yield* syncScopeSourceTypeDeclarationsWithDeps(deps, input.scopeId); |
| 104 | 113 | ||
| 105 | return true; | 114 | return true; |
| 106 | }); | 115 | }); |
| @@ -109,42 +118,42 @@ export const persistSourceWithDeps = ( · 2 unmodified lines | |||
| 109 | deps: RuntimeSourceStoreDeps, | 118 | deps: RuntimeSourceStoreDeps, |
| 110 | source: Source, | 119 | source: Source, |
| 111 | options: { | 120 | options: { |
| 112 | actorAccountId?: AccountId | null; | 121 | actorScopeId?: ScopeId | null; |
| 113 | } = {}, | 122 | } = {}, |
| 114 | deleteSecretMaterial: DeleteSecretMaterial, | 123 | deleteSecretMaterial: DeleteSecretMaterial, |
| 115 | ): Effect.Effect<Source, Error, never> => | 124 | ): Effect.Effect<Source, Error, never> => |
| 116 | Effect.gen(function* () { | 125 | Effect.gen(function* () { |
| 117 | const localWorkspace = yield* resolveRuntimeLocalWorkspaceFromDeps( | 126 | const localScope = yield* resolveRuntimeLocalScopeFromDeps( |
| 118 | deps, | 127 | deps, |
| 119 | source.workspaceId, | 128 | source.scopeId, |
| 120 | ); | 129 | ); |
| 121 | const nextSource = { | 130 | const nextSource = { |
| 122 | ...source, | 131 | ...source, |
| 123 | id: | 132 | id: |
| 124 | localWorkspace.loadedConfig.config?.sources?.[source.id] || | 133 | localScope.loadedConfig.config?.sources?.[source.id] || |
| 125 | localWorkspace.workspaceState.sources[source.id] | 134 | localScope.scopeState.sources[source.id] |
| 126 | ? source.id | 135 | ? source.id |
| 127 | : deriveLocalSourceId( | 136 | : deriveLocalSourceId( |
| 128 | source, | 137 | source, |
| 129 | new Set(Object.keys(localWorkspace.loadedConfig.config?.sources ?? {})), | 138 | new Set(Object.keys(localScope.loadedConfig.config?.sources ?? {})), |
| 130 | ), | 139 | ), |
| 131 | } satisfies Source; | 140 | } satisfies Source; |
| 132 | const existingAuthArtifacts = | 141 | const existingAuthArtifacts = |
| 133 | yield* deps.executorState.authArtifacts.listByWorkspaceAndSourceId({ | 142 | yield* deps.executorState.authArtifacts.listByScopeAndSourceId({ |
| 134 | workspaceId: nextSource.workspaceId, | 143 | scopeId: nextSource.scopeId, |
| 135 | sourceId: nextSource.id, | 144 | sourceId: nextSource.id, |
| 136 | }); | 145 | }); |
| 137 | const existingRuntimeAuthArtifact = selectExactAuthArtifact({ | 146 | const existingRuntimeAuthArtifact = selectExactAuthArtifact({ |
| 138 | authArtifacts: existingAuthArtifacts, | 147 | authArtifacts: existingAuthArtifacts, |
| 139 | actorAccountId: options.actorAccountId, | 148 | actorScopeId: options.actorScopeId, |
| 140 | slot: "runtime", | 149 | slot: "runtime", |
| 141 | }); | 150 | }); |
| 142 | const existingImportAuthArtifact = selectExactAuthArtifact({ | 151 | const existingImportAuthArtifact = selectExactAuthArtifact({ |
| 143 | authArtifacts: existingAuthArtifacts, | 152 | authArtifacts: existingAuthArtifacts, |
| 144 | actorAccountId: options.actorAccountId, | 153 | actorScopeId: options.actorScopeId, |
| 145 | slot: "import", | 154 | slot: "import", |
| 146 | }); | 155 | }); |
| 147 | const projectConfig = cloneJson(localWorkspace.loadedConfig.projectConfig ?? {}); | 156 | const projectConfig = cloneJson(localScope.loadedConfig.projectConfig ?? {}); |
| 148 | const sources = { | 157 | const sources = { |
| 149 | ...projectConfig.sources, | 158 | ...projectConfig.sources, |
| 150 | }; | 159 | }; |
| @@ -152,9 +161,9 @@ export const persistSourceWithDeps = ( · 1 unmodified line | |||
| 152 | sources[nextSource.id] = configSourceFromLocalSource({ | 161 | sources[nextSource.id] = configSourceFromLocalSource({ |
| 153 | source: nextSource, | 162 | source: nextSource, |
| 154 | existingConfigAuth: existingConfigSource?.connection.auth, | 163 | existingConfigAuth: existingConfigSource?.connection.auth, |
| 155 | config: localWorkspace.loadedConfig.config, | 164 | config: localScope.loadedConfig.config, |
| 156 | }); | 165 | }); |
| 157 | yield* localWorkspace.workspaceConfigStore.writeProject({ | 166 | yield* localScope.scopeConfigStore.writeProject({ |
| 158 | config: { | 167 | config: { |
| 159 | ...projectConfig, | 168 | ...projectConfig, |
| 160 | sources, | 169 | sources, |
| @@ -165,7 +174,7 @@ export const persistSourceWithDeps = ( · 4 unmodified lines | |||
| 165 | source: nextSource, | 174 | source: nextSource, |
| 166 | catalogId: stableSourceCatalogId(nextSource), | 175 | catalogId: stableSourceCatalogId(nextSource), |
| 167 | catalogRevisionId: stableSourceCatalogRevisionId(nextSource), | 176 | catalogRevisionId: stableSourceCatalogRevisionId(nextSource), |
| 168 | actorAccountId: options.actorAccountId, | 177 | actorScopeId: options.actorScopeId, |
| 169 | existingRuntimeAuthArtifactId: existingRuntimeAuthArtifact?.id ?? null, | 178 | existingRuntimeAuthArtifactId: existingRuntimeAuthArtifact?.id ?? null, |
| 170 | existingImportAuthArtifactId: existingImportAuthArtifact?.id ?? null, | 179 | existingImportAuthArtifactId: existingImportAuthArtifact?.id ?? null, |
| 171 | }); | 180 | }); |
| @@ -176,10 +185,10 @@ export const persistSourceWithDeps = ( · 4 unmodified lines | |||
| 176 | authArtifactId: existingRuntimeAuthArtifact.id, | 185 | authArtifactId: existingRuntimeAuthArtifact.id, |
| 177 | }, deleteSecretMaterial); | 186 | }, deleteSecretMaterial); |
| 178 | } | 187 | } |
| 179 | yield* deps.executorState.authArtifacts.removeByWorkspaceSourceAndActor({ | 188 | yield* deps.executorState.authArtifacts.removeByScopeSourceAndActor({ |
| 180 | workspaceId: nextSource.workspaceId, | 189 | scopeId: nextSource.scopeId, |
| 181 | sourceId: nextSource.id, | 190 | sourceId: nextSource.id, |
| 182 | actorAccountId: options.actorAccountId ?? null, | 191 | actorScopeId: options.actorScopeId ?? null, |
| 183 | slot: "runtime", | 192 | slot: "runtime", |
| 184 | }); | 193 | }); |
| 185 | } else { | 194 | } else { |
| @@ -205,10 +214,10 @@ export const persistSourceWithDeps = ( · 19 unmodified lines | |||
| 205 | authArtifactId: existingImportAuthArtifact.id, | 214 | authArtifactId: existingImportAuthArtifact.id, |
| 206 | }, deleteSecretMaterial); | 215 | }, deleteSecretMaterial); |
| 207 | } | 216 | } |
| 208 | yield* deps.executorState.authArtifacts.removeByWorkspaceSourceAndActor({ | 217 | yield* deps.executorState.authArtifacts.removeByScopeSourceAndActor({ |
| 209 | workspaceId: nextSource.workspaceId, | 218 | scopeId: nextSource.scopeId, |
| 210 | sourceId: nextSource.id, | 219 | sourceId: nextSource.id, |
| 211 | actorAccountId: options.actorAccountId ?? null, | 220 | actorScopeId: options.actorScopeId ?? null, |
| 212 | slot: "import", | 221 | slot: "import", |
| 213 | }); | 222 | }); |
| 214 | } else { | 223 | } else { |
| @@ -249,17 +258,17 @@ export const persistSourceWithDeps = ( · 34 unmodified lines | |||
| 249 | [...previousGrantIds].filter((grantId) => !nextGrantIds.has(grantId)), | 258 | [...previousGrantIds].filter((grantId) => !nextGrantIds.has(grantId)), |
| 250 | (grantId) => | 259 | (grantId) => |
| 251 | markProviderGrantOrphanedIfUnused(deps.executorState, { | 260 | markProviderGrantOrphanedIfUnused(deps.executorState, { |
| 252 | workspaceId: nextSource.workspaceId, | 261 | scopeId: nextSource.scopeId, |
| 253 | grantId, | 262 | grantId, |
| 254 | }), | 263 | }), |
| 255 | { discard: true }, | 264 | { discard: true }, |
| 256 | ); | 265 | ); |
| 257 | 266 | ||
| 258 | const existingSourceState = localWorkspace.workspaceState.sources[nextSource.id]; | 267 | const existingSourceState = localScope.scopeState.sources[nextSource.id]; |
| 259 | const workspaceState: LocalWorkspaceState = { | 268 | const scopeState: LocalScopeState = { |
| 260 | ...localWorkspace.workspaceState, | 269 | ...localScope.scopeState, |
| 261 | sources: { | 270 | sources: { |
| 262 | ...localWorkspace.workspaceState.sources, | 271 | ...localScope.scopeState.sources, |
| 263 | [nextSource.id]: { | 272 | [nextSource.id]: { |
| 264 | status: nextSource.status, | 273 | status: nextSource.status, |
| 265 | lastError: nextSource.lastError, | 274 | lastError: nextSource.lastError, |
| @@ -269,27 +278,27 @@ export const persistSourceWithDeps = ( · 3 unmodified lines | |||
| 269 | }, | 278 | }, |
| 270 | }, | 279 | }, |
| 271 | }; | 280 | }; |
| 272 | yield* localWorkspace.workspaceStateStore.write({ | 281 | yield* localScope.scopeStateStore.write({ |
| 273 | state: workspaceState, | 282 | state: scopeState, |
| 274 | }); | 283 | }); |
| 275 | 284 | ||
| 276 | if (shouldRefreshWorkspaceDeclarationsAfterPersist(nextSource)) { | 285 | if (shouldRefreshScopeDeclarationsAfterPersist(nextSource)) { |
| 277 | yield* syncWorkspaceSourceTypeDeclarationsWithDeps( | 286 | yield* syncScopeSourceTypeDeclarationsWithDeps( |
| 278 | deps, | 287 | deps, |
| 279 | nextSource.workspaceId, | 288 | nextSource.scopeId, |
| 280 | options, | 289 | options, |
| 281 | ); | 290 | ); |
| 282 | } | 291 | } |
| 283 | 292 | ||
| 284 | return yield* loadSourceByIdWithDeps(deps, { | 293 | return yield* loadSourceByIdWithDeps(deps, { |
| 285 | workspaceId: nextSource.workspaceId, | 294 | scopeId: nextSource.scopeId, |
| 286 | sourceId: nextSource.id, | 295 | sourceId: nextSource.id, |
| 287 | actorAccountId: options.actorAccountId, | 296 | actorScopeId: options.actorScopeId, |
| 288 | }); | 297 | }); |
| 289 | }).pipe( | 298 | }).pipe( |
| 290 | Effect.withSpan("source.store.persist", { | 299 | Effect.withSpan("source.store.persist", { |
| 291 | attributes: { | 300 | attributes: { |
| 292 | "executor.workspace.id": source.workspaceId, | 301 | "executor.scope.id": source.scopeId, |
| 293 | "executor.source.id": source.id, | 302 | "executor.source.id": source.id, |
| 294 | "executor.source.kind": source.kind, | 303 | "executor.source.kind": source.kind, |
| 295 | "executor.source.status": source.status, | 304 | "executor.source.status": source.status, |
| @@ -1,25 +1,36 @@ | |||
| 1 | import type { | 1 | import type { |
| 2 | AccountId, | 2 | ScopeId, |
| 3 | AuthArtifact, | 3 | AuthArtifact, |
| 4 | Source, | 4 | Source, |
| 5 | SourceId, | 5 | SourceId, |
| 6 | WorkspaceId, | ||
| 7 | } from "#schema"; | 6 | } from "#schema"; |
| 8 | import { SourceIdSchema } from "#schema"; | 7 | import { |
| 8 | SourceIdSchema, | ||
| 9 | } from "#schema"; | ||
| 9 | import * as Effect from "effect/Effect"; | 10 | import * as Effect from "effect/Effect"; |
| 10 | 11 | ||
| 11 | import { sourceAuthFromAuthArtifact } from "../../auth/auth-artifacts"; | 12 | import { |
| 12 | import { authArtifactSecretMaterialRefs } from "../../auth/auth-artifacts"; | 13 | sourceAuthFromAuthArtifact, |
| 13 | import type { LoadedLocalExecutorConfig } from "../../workspace-config"; | 14 | } from "../../auth/auth-artifacts"; |
| 15 | import { | ||
| 16 | authArtifactSecretMaterialRefs, | ||
| 17 | } from "../../auth/auth-artifacts"; | ||
| 18 | import type { | ||
| 19 | LoadedLocalExecutorConfig, | ||
| 20 | } from "../../scope-config"; | ||
| 14 | import { | 21 | import { |
| 15 | LocalConfiguredSourceNotFoundError, | 22 | LocalConfiguredSourceNotFoundError, |
| 16 | RuntimeLocalWorkspaceMismatchError, | 23 | RuntimeLocalScopeMismatchError, |
| 17 | RuntimeLocalWorkspaceUnavailableError, | 24 | RuntimeLocalScopeUnavailableError, |
| 18 | } from "../../workspace-errors"; | 25 | } from "../../scope-errors"; |
| 19 | import type { LocalWorkspaceState } from "../../workspace-state"; | 26 | import type { |
| 20 | import { getSourceAdapter } from "../source-adapters"; | 27 | LocalScopeState, |
| 28 | } from "../../scope-state"; | ||
| 29 | import { | ||
| 30 | getSourceAdapter, | ||
| 31 | } from "../source-adapters"; | ||
| 21 | import { | 32 | import { |
| 22 | resolveRuntimeLocalWorkspaceFromDeps, | 33 | resolveRuntimeLocalScopeFromDeps, |
| 23 | type RuntimeSourceStoreDeps, | 34 | type RuntimeSourceStoreDeps, |
| 24 | } from "./deps"; | 35 | } from "./deps"; |
| 25 | import { | 36 | import { |
| @@ -31,11 +42,11 @@ import { · 5 unmodified lines | |||
| 31 | } from "./config"; | 42 | } from "./config"; |
| 32 | 43 | ||
| 33 | export const buildLocalSourceRecord = (input: { | 44 | export const buildLocalSourceRecord = (input: { |
| 34 | workspaceId: WorkspaceId; | 45 | scopeId: ScopeId; |
| 35 | loadedConfig: LoadedLocalExecutorConfig; | 46 | loadedConfig: LoadedLocalExecutorConfig; |
| 36 | workspaceState: LocalWorkspaceState; | 47 | scopeState: LocalScopeState; |
| 37 | sourceId: SourceId; | 48 | sourceId: SourceId; |
| 38 | actorAccountId?: AccountId | null; | 49 | actorScopeId?: ScopeId | null; |
| 39 | authArtifacts: ReadonlyArray<AuthArtifact>; | 50 | authArtifacts: ReadonlyArray<AuthArtifact>; |
| 40 | }): Effect.Effect< | 51 | }): Effect.Effect< |
| 41 | { | 52 | { |
| @@ -54,11 +65,11 @@ export const buildLocalSourceRecord = (input: { · 12 unmodified lines | |||
| 54 | }); | 65 | }); |
| 55 | } | 66 | } |
| 56 | 67 | ||
| 57 | const existingState = input.workspaceState.sources[input.sourceId]; | 68 | const existingState = input.scopeState.sources[input.sourceId]; |
| 58 | const adapter = getSourceAdapter(sourceConfig.kind); | 69 | const adapter = getSourceAdapter(sourceConfig.kind); |
| 59 | const baseSource = (yield* adapter.validateSource({ | 70 | const baseSource = (yield* adapter.validateSource({ |
| 60 | id: SourceIdSchema.make(input.sourceId), | 71 | id: SourceIdSchema.make(input.sourceId), |
| 61 | workspaceId: input.workspaceId, | 72 | scopeId: input.scopeId, |
| 62 | name: trimOrNull(sourceConfig.name) ?? input.sourceId, | 73 | name: trimOrNull(sourceConfig.name) ?? input.sourceId, |
| 63 | kind: sourceConfig.kind, | 74 | kind: sourceConfig.kind, |
| 64 | endpoint: sourceConfig.connection.endpoint.trim(), | 75 | endpoint: sourceConfig.connection.endpoint.trim(), |
| @@ -86,14 +97,14 @@ export const buildLocalSourceRecord = (input: { · 21 unmodified lines | |||
| 86 | authArtifacts: input.authArtifacts.filter( | 97 | authArtifacts: input.authArtifacts.filter( |
| 87 | (artifactItem) => artifactItem.sourceId === baseSource.id, | 98 | (artifactItem) => artifactItem.sourceId === baseSource.id, |
| 88 | ), | 99 | ), |
| 89 | actorAccountId: input.actorAccountId, | 100 | actorScopeId: input.actorScopeId, |
| 90 | slot: "runtime", | 101 | slot: "runtime", |
| 91 | }); | 102 | }); |
| 92 | const importAuthArtifact = selectPreferredAuthArtifact({ | 103 | const importAuthArtifact = selectPreferredAuthArtifact({ |
| 93 | authArtifacts: input.authArtifacts.filter( | 104 | authArtifacts: input.authArtifacts.filter( |
| 94 | (artifactItem) => artifactItem.sourceId === baseSource.id, | 105 | (artifactItem) => artifactItem.sourceId === baseSource.id, |
| 95 | ), | 106 | ), |
| 96 | actorAccountId: input.actorAccountId, | 107 | actorScopeId: input.actorScopeId, |
| 97 | slot: "import", | 108 | slot: "import", |
| 98 | }); | 109 | }); |
| 99 | 110 | ||
| @@ -119,36 +130,36 @@ export const buildLocalSourceRecord = (input: { · 19 unmodified lines | |||
| 119 | 130 | ||
| 120 | export const loadSourcesInWorkspaceWithDeps = ( | 131 | export const loadSourcesInWorkspaceWithDeps = ( |
| 121 | deps: RuntimeSourceStoreDeps, | 132 | deps: RuntimeSourceStoreDeps, |
| 122 | workspaceId: WorkspaceId, | 133 | scopeId: ScopeId, |
| 123 | options: { | 134 | options: { |
| 124 | actorAccountId?: AccountId | null; | 135 | actorScopeId?: ScopeId | null; |
| 125 | } = {}, | 136 | } = {}, |
| 126 | ): Effect.Effect< | 137 | ): Effect.Effect< |
| 127 | readonly Source[], | 138 | readonly Source[], |
| 128 | | RuntimeLocalWorkspaceUnavailableError | 139 | | RuntimeLocalScopeUnavailableError |
| 129 | | RuntimeLocalWorkspaceMismatchError | 140 | | RuntimeLocalScopeMismatchError |
| 130 | | LocalConfiguredSourceNotFoundError | 141 | | LocalConfiguredSourceNotFoundError |
| 131 | | Error, | 142 | | Error, |
| 132 | never | 143 | never |
| 133 | > => | 144 | > => |
| 134 | Effect.gen(function* () { | 145 | Effect.gen(function* () { |
| 135 | const localWorkspace = yield* resolveRuntimeLocalWorkspaceFromDeps( | 146 | const localScope = yield* resolveRuntimeLocalScopeFromDeps( |
| 136 | deps, | 147 | deps, |
| 137 | workspaceId, | 148 | scopeId, |
| 138 | ); | 149 | ); |
| 139 | const authArtifacts = yield* deps.executorState.authArtifacts.listByWorkspaceId( | 150 | const authArtifacts = yield* deps.executorState.authArtifacts.listByScopeId( |
| 140 | workspaceId, | 151 | scopeId, |
| 141 | ); | 152 | ); |
| 142 | const sources = yield* Effect.forEach( | 153 | const sources = yield* Effect.forEach( |
| 143 | Object.keys(localWorkspace.loadedConfig.config?.sources ?? {}), | 154 | Object.keys(localScope.loadedConfig.config?.sources ?? {}), |
| 144 | (sourceId) => | 155 | (sourceId) => |
| 145 | Effect.map( | 156 | Effect.map( |
| 146 | buildLocalSourceRecord({ | 157 | buildLocalSourceRecord({ |
| 147 | workspaceId, | 158 | scopeId, |
| 148 | loadedConfig: localWorkspace.loadedConfig, | 159 | loadedConfig: localScope.loadedConfig, |
| 149 | workspaceState: localWorkspace.workspaceState, | 160 | scopeState: localScope.scopeState, |
| 150 | sourceId: SourceIdSchema.make(sourceId), | 161 | sourceId: SourceIdSchema.make(sourceId), |
| 151 | actorAccountId: options.actorAccountId, | 162 | actorScopeId: options.actorScopeId, |
| 152 | authArtifacts, | 163 | authArtifacts, |
| 153 | }), | 164 | }), |
| 154 | ({ source }) => source, | 165 | ({ source }) => source, |
| @@ -157,28 +168,28 @@ export const loadSourcesInWorkspaceWithDeps = ( · 2 unmodified lines | |||
| 157 | yield* Effect.annotateCurrentSpan("executor.source.count", sources.length); | 168 | yield* Effect.annotateCurrentSpan("executor.source.count", sources.length); |
| 158 | return sources; | 169 | return sources; |
| 159 | }).pipe( | 170 | }).pipe( |
| 160 | Effect.withSpan("source.store.load_workspace", { | 171 | Effect.withSpan("source.store.load_scope", { |
| 161 | attributes: { | 172 | attributes: { |
| 162 | "executor.workspace.id": workspaceId, | 173 | "executor.scope.id": scopeId, |
| 163 | }, | 174 | }, |
| 164 | }), | 175 | }), |
| 165 | ); | 176 | ); |
| 166 | 177 | ||
| 167 | export const syncWorkspaceSourceTypeDeclarationsWithDeps = ( | 178 | export const syncScopeSourceTypeDeclarationsWithDeps = ( |
| 168 | deps: RuntimeSourceStoreDeps, | 179 | deps: RuntimeSourceStoreDeps, |
| 169 | workspaceId: WorkspaceId, | 180 | scopeId: ScopeId, |
| 170 | options: { | 181 | options: { |
| 171 | actorAccountId?: AccountId | null; | 182 | actorScopeId?: ScopeId | null; |
| 172 | } = {}, | 183 | } = {}, |
| 173 | ): Effect.Effect<void, Error, never> => | 184 | ): Effect.Effect<void, Error, never> => |
| 174 | Effect.gen(function* () { | 185 | Effect.gen(function* () { |
| 175 | const localWorkspace = yield* resolveRuntimeLocalWorkspaceFromDeps( | 186 | const localScope = yield* resolveRuntimeLocalScopeFromDeps( |
| 176 | deps, | 187 | deps, |
| 177 | workspaceId, | 188 | scopeId, |
| 178 | ); | 189 | ); |
| 179 | const sources = yield* loadSourcesInWorkspaceWithDeps( | 190 | const sources = yield* loadSourcesInWorkspaceWithDeps( |
| 180 | deps, | 191 | deps, |
| 181 | workspaceId, | 192 | scopeId, |
| 182 | options, | 193 | options, |
| 183 | ); | 194 | ); |
| 184 | const entries = yield* Effect.forEach(sources, (source) => | 195 | const entries = yield* Effect.forEach(sources, (source) => |
| @@ -202,14 +213,14 @@ export const syncWorkspaceSourceTypeDeclarationsWithDeps = ( · 17 unmodified lines | |||
| 202 | ), | 213 | ), |
| 203 | }); | 214 | }); |
| 204 | }).pipe( | 215 | }).pipe( |
| 205 | Effect.withSpan("source.types.refresh_workspace.schedule", { | 216 | Effect.withSpan("source.types.refresh_scope.schedule", { |
| 206 | attributes: { | 217 | attributes: { |
| 207 | "executor.workspace.id": workspaceId, | 218 | "executor.scope.id": scopeId, |
| 208 | }, | 219 | }, |
| 209 | }), | 220 | }), |
| 210 | ); | 221 | ); |
| 211 | 222 | ||
| 212 | export const shouldRefreshWorkspaceDeclarationsAfterPersist = (source: Source): boolean => | 223 | export const shouldRefreshScopeDeclarationsAfterPersist = (source: Source): boolean => |
| 213 | source.enabled === false || | 224 | source.enabled === false || |
| 214 | source.status === "auth_required" || | 225 | source.status === "auth_required" || |
| 215 | source.status === "error" || | 226 | source.status === "error" || |
| @@ -217,24 +228,24 @@ export const shouldRefreshWorkspaceDeclarationsAfterPersist = (source: Source): · 1 unmodified line | |||
| 217 | 228 | ||
| 218 | export const listLinkedSecretSourcesInWorkspaceWithDeps = ( | 229 | export const listLinkedSecretSourcesInWorkspaceWithDeps = ( |
| 219 | deps: RuntimeSourceStoreDeps, | 230 | deps: RuntimeSourceStoreDeps, |
| 220 | workspaceId: WorkspaceId, | 231 | scopeId: ScopeId, |
| 221 | options: { | 232 | options: { |
| 222 | actorAccountId?: AccountId | null; | 233 | actorScopeId?: ScopeId | null; |
| 223 | } = {}, | 234 | } = {}, |
| 224 | ): Effect.Effect< | 235 | ): Effect.Effect< |
| 225 | Map<string, Array<{ sourceId: string; sourceName: string }>>, | 236 | Map<string, Array<{ sourceId: string; sourceName: string }>>, |
| 226 | | RuntimeLocalWorkspaceUnavailableError | 237 | | RuntimeLocalScopeUnavailableError |
| 227 | | RuntimeLocalWorkspaceMismatchError | 238 | | RuntimeLocalScopeMismatchError |
| 228 | | LocalConfiguredSourceNotFoundError | 239 | | LocalConfiguredSourceNotFoundError |
| 229 | | Error, | 240 | | Error, |
| 230 | never | 241 | never |
| 231 | > => | 242 | > => |
| 232 | Effect.gen(function* () { | 243 | Effect.gen(function* () { |
| 233 | const [sources, authArtifacts, materialIds] = yield* Effect.all([ | 244 | const [sources, authArtifacts, materialIds] = yield* Effect.all([ |
| 234 | loadSourcesInWorkspaceWithDeps(deps, workspaceId, { | 245 | loadSourcesInWorkspaceWithDeps(deps, scopeId, { |
| 235 | actorAccountId: options.actorAccountId, | 246 | actorScopeId: options.actorScopeId, |
| 236 | }), | 247 | }), |
| 237 | deps.executorState.authArtifacts.listByWorkspaceId(workspaceId), | 248 | deps.executorState.authArtifacts.listByScopeId(scopeId), |
| 238 | deps.executorState.secretMaterials.listAll().pipe( | 249 | deps.executorState.secretMaterials.listAll().pipe( |
| 239 | Effect.map( | 250 | Effect.map( |
| 240 | (materials) => new Set(materials.map((material) => String(material.id))), | 251 | (materials) => new Set(materials.map((material) => String(material.id))), |
| @@ -273,39 +284,39 @@ export const listLinkedSecretSourcesInWorkspaceWithDeps = ( · 32 unmodified lines | |||
| 273 | export const loadSourceByIdWithDeps = ( | 284 | export const loadSourceByIdWithDeps = ( |
| 274 | deps: RuntimeSourceStoreDeps, | 285 | deps: RuntimeSourceStoreDeps, |
| 275 | input: { | 286 | input: { |
| 276 | workspaceId: WorkspaceId; | 287 | scopeId: ScopeId; |
| 277 | sourceId: Source["id"]; | 288 | sourceId: Source["id"]; |
| 278 | actorAccountId?: AccountId | null; | 289 | actorScopeId?: ScopeId | null; |
| 279 | }, | 290 | }, |
| 280 | ): Effect.Effect< | 291 | ): Effect.Effect< |
| 281 | Source, | 292 | Source, |
| 282 | | RuntimeLocalWorkspaceUnavailableError | 293 | | RuntimeLocalScopeUnavailableError |
| 283 | | RuntimeLocalWorkspaceMismatchError | 294 | | RuntimeLocalScopeMismatchError |
| 284 | | LocalConfiguredSourceNotFoundError | 295 | | LocalConfiguredSourceNotFoundError |
| 285 | | Error, | 296 | | Error, |
| 286 | never | 297 | never |
| 287 | > => | 298 | > => |
| 288 | Effect.gen(function* () { | 299 | Effect.gen(function* () { |
| 289 | const localWorkspace = yield* resolveRuntimeLocalWorkspaceFromDeps( | 300 | const localScope = yield* resolveRuntimeLocalScopeFromDeps( |
| 290 | deps, | 301 | deps, |
| 291 | input.workspaceId, | 302 | input.scopeId, |
| 292 | ); | 303 | ); |
| 293 | const authArtifacts = yield* deps.executorState.authArtifacts.listByWorkspaceId( | 304 | const authArtifacts = yield* deps.executorState.authArtifacts.listByScopeId( |
| 294 | input.workspaceId, | 305 | input.scopeId, |
| 295 | ); | 306 | ); |
| 296 | if (!localWorkspace.loadedConfig.config?.sources?.[input.sourceId]) { | 307 | if (!localScope.loadedConfig.config?.sources?.[input.sourceId]) { |
| 297 | return yield* new LocalConfiguredSourceNotFoundError({ | 308 | return yield* new LocalConfiguredSourceNotFoundError({ |
| 298 | message: `Source not found: workspaceId=${input.workspaceId} sourceId=${input.sourceId}`, | 309 | message: `Source not found: scopeId=${input.scopeId} sourceId=${input.sourceId}`, |
| 299 | sourceId: input.sourceId, | 310 | sourceId: input.sourceId, |
| 300 | }); | 311 | }); |
| 301 | } | 312 | } |
| 302 | 313 | ||
| 303 | const localSource = yield* buildLocalSourceRecord({ | 314 | const localSource = yield* buildLocalSourceRecord({ |
| 304 | workspaceId: input.workspaceId, | 315 | scopeId: input.scopeId, |
| 305 | loadedConfig: localWorkspace.loadedConfig, | 316 | loadedConfig: localScope.loadedConfig, |
| 306 | workspaceState: localWorkspace.workspaceState, | 317 | scopeState: localScope.scopeState, |
| 307 | sourceId: input.sourceId, | 318 | sourceId: input.sourceId, |
| 308 | actorAccountId: input.actorAccountId, | 319 | actorScopeId: input.actorScopeId, |
| 309 | authArtifacts, | 320 | authArtifacts, |
| 310 | }); | 321 | }); |
| 311 | 322 | ||
| @@ -313,7 +324,7 @@ export const loadSourceByIdWithDeps = ( · 1 unmodified line | |||
| 313 | }).pipe( | 324 | }).pipe( |
| 314 | Effect.withSpan("source.store.load_by_id", { | 325 | Effect.withSpan("source.store.load_by_id", { |
| 315 | attributes: { | 326 | attributes: { |
| 316 | "executor.workspace.id": input.workspaceId, | 327 | "executor.scope.id": input.scopeId, |
| 317 | "executor.source.id": input.sourceId, | 328 | "executor.source.id": input.sourceId, |
| 318 | }, | 329 | }, |
| 319 | }), | 330 | }), |
| @@ -1,78 +0,0 @@ | |||
| 1 | import * as Context from "effect/Context"; | ||
| 2 | import * as Effect from "effect/Effect"; | ||
| 3 | import * as Layer from "effect/Layer"; | ||
| 4 | import * as Option from "effect/Option"; | ||
| 5 | |||
| 6 | import type { AccountId, WorkspaceId } from "#schema"; | ||
| 7 | import type { ExecutorWorkspaceContext } from "../../workspace"; | ||
| 8 | import type { LoadedLocalExecutorConfig } from "../workspace-config"; | ||
| 9 | import { | ||
| 10 | RuntimeLocalWorkspaceMismatchError, | ||
| 11 | RuntimeLocalWorkspaceUnavailableError, | ||
| 12 | } from "../workspace-errors"; | ||
| 13 | |||
| 14 | export type RuntimeLocalWorkspaceState = { | ||
| 15 | workspace: ExecutorWorkspaceContext; | ||
| 16 | installation: { | ||
| 17 | workspaceId: WorkspaceId; | ||
| 18 | accountId: AccountId; | ||
| 19 | }; | ||
| 20 | loadedConfig: LoadedLocalExecutorConfig; | ||
| 21 | }; | ||
| 22 | |||
| 23 | export class RuntimeLocalWorkspaceService extends Context.Tag( | ||
| 24 | "#runtime/RuntimeLocalWorkspaceService", | ||
| 25 | )<RuntimeLocalWorkspaceService, RuntimeLocalWorkspaceState>() {} | ||
| 26 | |||
| 27 | export const RuntimeLocalWorkspaceLive = ( | ||
| 28 | runtimeLocalWorkspace: RuntimeLocalWorkspaceState, | ||
| 29 | ) => Layer.succeed(RuntimeLocalWorkspaceService, runtimeLocalWorkspace); | ||
| 30 | |||
| 31 | export const provideOptionalRuntimeLocalWorkspace = <A, E, R>( | ||
| 32 | effect: Effect.Effect<A, E, R>, | ||
| 33 | runtimeLocalWorkspace: RuntimeLocalWorkspaceState | null | undefined, | ||
| 34 | ): Effect.Effect<A, E, R> => | ||
| 35 | runtimeLocalWorkspace === null || runtimeLocalWorkspace === undefined | ||
| 36 | ? effect | ||
| 37 | : effect.pipe(Effect.provide(RuntimeLocalWorkspaceLive(runtimeLocalWorkspace))); | ||
| 38 | |||
| 39 | export const getRuntimeLocalWorkspaceOption = () => | ||
| 40 | Effect.contextWith((context) => | ||
| 41 | Context.getOption(context, RuntimeLocalWorkspaceService), | ||
| 42 | ).pipe( | ||
| 43 | Effect.map((option) => (Option.isSome(option) ? option.value : null)), | ||
| 44 | ) as Effect.Effect<RuntimeLocalWorkspaceState | null, never, never>; | ||
| 45 | |||
| 46 | export const requireRuntimeLocalWorkspace = ( | ||
| 47 | workspaceId?: WorkspaceId, | ||
| 48 | ): Effect.Effect< | ||
| 49 | RuntimeLocalWorkspaceState, | ||
| 50 | RuntimeLocalWorkspaceUnavailableError | RuntimeLocalWorkspaceMismatchError, | ||
| 51 | never | ||
| 52 | > => | ||
| 53 | Effect.gen(function* () { | ||
| 54 | const runtimeLocalWorkspace = yield* getRuntimeLocalWorkspaceOption(); | ||
| 55 | if (runtimeLocalWorkspace === null) { | ||
| 56 | return yield* new RuntimeLocalWorkspaceUnavailableError({ | ||
| 57 | message: "Runtime local workspace is unavailable", | ||
| 58 | }); | ||
| 59 | } | ||
| 60 | |||
| 61 | if ( | ||
| 62 | workspaceId !== undefined | ||
| 63 | && runtimeLocalWorkspace.installation.workspaceId !== workspaceId | ||
| 64 | ) { | ||
| 65 | return yield* new RuntimeLocalWorkspaceMismatchError({ | ||
| 66 | message: `Workspace ${workspaceId} is not the active local workspace ${runtimeLocalWorkspace.installation.workspaceId}`, | ||
| 67 | requestedWorkspaceId: workspaceId, | ||
| 68 | activeWorkspaceId: runtimeLocalWorkspace.installation.workspaceId, | ||
| 69 | }); | ||
| 70 | } | ||
| 71 | |||
| 72 | return runtimeLocalWorkspace; | ||
| 73 | }); | ||
| 74 | |||
| 75 | export const requireRuntimeLocalAccountId = (workspaceId?: WorkspaceId) => | ||
| 76 | requireRuntimeLocalWorkspace(workspaceId).pipe( | ||
| 77 | Effect.map((runtimeLocalWorkspace) => runtimeLocalWorkspace.installation.accountId), | ||
| 78 | ); | ||
| @@ -1,4 +1,6 @@ | |||
| 1 | import { Schema } from "effect"; | 1 | import { |
| 2 | Schema, | ||
| 3 | } from "effect"; | ||
| 2 | 4 | ||
| 3 | export const TimestampMsSchema = Schema.Number; | 5 | export const TimestampMsSchema = Schema.Number; |
| 4 | 6 | ||
| @@ -54,8 +54,8 @@ export { · 53 unmodified lines | |||
| 54 | type SourceAuthSessionStatus, | 54 | type SourceAuthSessionStatus, |
| 55 | } from "./models/source-auth-session"; | 55 | } from "./models/source-auth-session"; |
| 56 | export { | 56 | export { |
| 57 | LocalWorkspacePolicyApprovalModeSchema, | 57 | LocalScopePolicyApprovalModeSchema, |
| 58 | LocalWorkspacePolicyEffectSchema, | 58 | LocalScopePolicyEffectSchema, |
| 59 | type LocalWorkspacePolicyApprovalMode, | 59 | type LocalScopePolicyApprovalMode, |
| 60 | type LocalWorkspacePolicyEffect, | 60 | type LocalScopePolicyEffect, |
| 61 | } from "./models/policy"; | 61 | } from "./models/policy"; |
| @@ -1,7 +1,8 @@ | |||
| 1 | import { Schema } from "effect"; | 1 | import { |
| 2 | Schema, | ||
| 3 | } from "effect"; | ||
| 2 | 4 | ||
| 3 | export const AccountIdSchema = Schema.String.pipe(Schema.brand("AccountId")); | 5 | export const ScopeIdSchema = Schema.String.pipe(Schema.brand("ScopeId")); |
| 4 | export const WorkspaceIdSchema = Schema.String.pipe(Schema.brand("WorkspaceId")); | ||
| 5 | export const SourceIdSchema = Schema.String.pipe(Schema.brand("SourceId")); | 6 | export const SourceIdSchema = Schema.String.pipe(Schema.brand("SourceId")); |
| 6 | export const SourceCatalogIdSchema = Schema.String.pipe(Schema.brand("SourceCatalogId")); | 7 | export const SourceCatalogIdSchema = Schema.String.pipe(Schema.brand("SourceCatalogId")); |
| 7 | export const SourceCatalogRevisionIdSchema = Schema.String.pipe( | 8 | export const SourceCatalogRevisionIdSchema = Schema.String.pipe( |
| @@ -17,11 +18,11 @@ export const AuthLeaseIdSchema = Schema.String.pipe( · 9 unmodified lines | |||
| 17 | Schema.brand("AuthLeaseId"), | 18 | Schema.brand("AuthLeaseId"), |
| 18 | ); | 19 | ); |
| 19 | export const CredentialIdSchema = AuthArtifactIdSchema; | 20 | export const CredentialIdSchema = AuthArtifactIdSchema; |
| 20 | export const WorkspaceSourceOauthClientIdSchema = Schema.String.pipe( | 21 | export const ScopedSourceOauthClientIdSchema = Schema.String.pipe( |
| 21 | Schema.brand("WorkspaceSourceOauthClientId"), | 22 | Schema.brand("ScopedSourceOauthClientId"), |
| 22 | ); | 23 | ); |
| 23 | export const WorkspaceOauthClientIdSchema = Schema.String.pipe( | 24 | export const ScopeOauthClientIdSchema = Schema.String.pipe( |
| 24 | Schema.brand("WorkspaceOauthClientId"), | 25 | Schema.brand("ScopeOauthClientId"), |
| 25 | ); | 26 | ); |
| 26 | export const ProviderAuthGrantIdSchema = Schema.String.pipe( | 27 | export const ProviderAuthGrantIdSchema = Schema.String.pipe( |
| 27 | Schema.brand("ProviderAuthGrantId"), | 28 | Schema.brand("ProviderAuthGrantId"), |
| @@ -38,8 +39,7 @@ export const ExecutionStepIdSchema = Schema.String.pipe( · 10 unmodified lines | |||
| 38 | Schema.brand("ExecutionStepId"), | 39 | Schema.brand("ExecutionStepId"), |
| 39 | ); | 40 | ); |
| 40 | 41 | ||
| 41 | export type AccountId = typeof AccountIdSchema.Type; | 42 | export type ScopeId = typeof ScopeIdSchema.Type; |
| 42 | export type WorkspaceId = typeof WorkspaceIdSchema.Type; | ||
| 43 | export type SourceId = typeof SourceIdSchema.Type; | 43 | export type SourceId = typeof SourceIdSchema.Type; |
| 44 | export type SourceCatalogId = typeof SourceCatalogIdSchema.Type; | 44 | export type SourceCatalogId = typeof SourceCatalogIdSchema.Type; |
| 45 | export type SourceCatalogRevisionId = typeof SourceCatalogRevisionIdSchema.Type; | 45 | export type SourceCatalogRevisionId = typeof SourceCatalogRevisionIdSchema.Type; |
| @@ -47,8 +47,8 @@ export type SourceAuthSessionId = typeof SourceAuthSessionIdSchema.Type; · 1 unmodified line | |||
| 47 | export type AuthArtifactId = typeof AuthArtifactIdSchema.Type; | 47 | export type AuthArtifactId = typeof AuthArtifactIdSchema.Type; |
| 48 | export type AuthLeaseId = typeof AuthLeaseIdSchema.Type; | 48 | export type AuthLeaseId = typeof AuthLeaseIdSchema.Type; |
| 49 | export type CredentialId = typeof CredentialIdSchema.Type; | 49 | export type CredentialId = typeof CredentialIdSchema.Type; |
| 50 | export type WorkspaceSourceOauthClientId = typeof WorkspaceSourceOauthClientIdSchema.Type; | 50 | export type ScopedSourceOauthClientId = typeof ScopedSourceOauthClientIdSchema.Type; |
| 51 | export type WorkspaceOauthClientId = typeof WorkspaceOauthClientIdSchema.Type; | 51 | export type ScopeOauthClientId = typeof ScopeOauthClientIdSchema.Type; |
| 52 | export type ProviderAuthGrantId = typeof ProviderAuthGrantIdSchema.Type; | 52 | export type ProviderAuthGrantId = typeof ProviderAuthGrantIdSchema.Type; |
| 53 | export type SecretMaterialId = typeof SecretMaterialIdSchema.Type; | 53 | export type SecretMaterialId = typeof SecretMaterialIdSchema.Type; |
| 54 | export type PolicyId = typeof PolicyIdSchema.Type; | 54 | export type PolicyId = typeof PolicyIdSchema.Type; |
| @@ -7,7 +7,7 @@ export * from "./models/source-catalog"; · 6 unmodified lines | |||
| 7 | export * from "./models/auth-artifact"; | 7 | export * from "./models/auth-artifact"; |
| 8 | export * from "./models/auth-lease"; | 8 | export * from "./models/auth-lease"; |
| 9 | export * from "./models/source-oauth-client"; | 9 | export * from "./models/source-oauth-client"; |
| 10 | export * from "./models/workspace-oauth-client"; | 10 | export * from "./models/scope-oauth-client"; |
| 11 | export * from "./models/provider-auth-grant"; | 11 | export * from "./models/provider-auth-grant"; |
| 12 | export * from "./models/secret-material"; | 12 | export * from "./models/secret-material"; |
| 13 | export * from "./models/source-auth-session"; | 13 | export * from "./models/source-auth-session"; |
| @@ -1,13 +1,16 @@ | |||
| 1 | import { Schema } from "effect"; | 1 | import { |
| 2 | Schema, | ||
| 3 | } from "effect"; | ||
| 2 | import * as Option from "effect/Option"; | 4 | import * as Option from "effect/Option"; |
| 3 | 5 | ||
| 4 | import { TimestampMsSchema } from "../common"; | ||
| 5 | import { | 6 | import { |
| 6 | AccountIdSchema, | 7 | TimestampMsSchema, |
| 8 | } from "../common"; | ||
| 9 | import { | ||
| 10 | ScopeIdSchema, | ||
| 7 | AuthArtifactIdSchema, | 11 | AuthArtifactIdSchema, |
| 8 | ProviderAuthGrantIdSchema, | 12 | ProviderAuthGrantIdSchema, |
| 9 | SourceIdSchema, | 13 | SourceIdSchema, |
| 10 | WorkspaceIdSchema, | ||
| 11 | } from "../ids"; | 14 | } from "../ids"; |
| 12 | 15 | ||
| 13 | export const SecretRefSchema = Schema.Struct({ | 16 | export const SecretRefSchema = Schema.Struct({ |
| @@ -207,9 +210,9 @@ const decodeAuthGrantSetOption = Schema.decodeUnknownOption(AuthGrantSetJsonSche · 193 unmodified lines | |||
| 207 | 210 | ||
| 208 | export const AuthArtifactSchema = Schema.Struct({ | 211 | export const AuthArtifactSchema = Schema.Struct({ |
| 209 | id: AuthArtifactIdSchema, | 212 | id: AuthArtifactIdSchema, |
| 210 | workspaceId: WorkspaceIdSchema, | 213 | scopeId: ScopeIdSchema, |
| 211 | sourceId: SourceIdSchema, | 214 | sourceId: SourceIdSchema, |
| 212 | actorAccountId: Schema.NullOr(AccountIdSchema), | 215 | actorScopeId: Schema.NullOr(ScopeIdSchema), |
| 213 | slot: AuthArtifactSlotSchema, | 216 | slot: AuthArtifactSlotSchema, |
| 214 | artifactKind: AuthArtifactKindSchema, | 217 | artifactKind: AuthArtifactKindSchema, |
| 215 | configJson: Schema.String, | 218 | configJson: Schema.String, |
| @@ -1,13 +1,16 @@ | |||
| 1 | import { Schema } from "effect"; | 1 | import { |
| 2 | Schema, | ||
| 3 | } from "effect"; | ||
| 2 | import * as Option from "effect/Option"; | 4 | import * as Option from "effect/Option"; |
| 3 | 5 | ||
| 4 | import { TimestampMsSchema } from "../common"; | ||
| 5 | import { | 6 | import { |
| 6 | AccountIdSchema, | 7 | TimestampMsSchema, |
| 8 | } from "../common"; | ||
| 9 | import { | ||
| 10 | ScopeIdSchema, | ||
| 7 | AuthArtifactIdSchema, | 11 | AuthArtifactIdSchema, |
| 8 | AuthLeaseIdSchema, | 12 | AuthLeaseIdSchema, |
| 9 | SourceIdSchema, | 13 | SourceIdSchema, |
| 10 | WorkspaceIdSchema, | ||
| 11 | } from "../ids"; | 14 | } from "../ids"; |
| 12 | 15 | ||
| 13 | import { | 16 | import { |
| @@ -19,9 +22,9 @@ import { · 5 unmodified lines | |||
| 19 | export const AuthLeaseSchema = Schema.Struct({ | 22 | export const AuthLeaseSchema = Schema.Struct({ |
| 20 | id: AuthLeaseIdSchema, | 23 | id: AuthLeaseIdSchema, |
| 21 | authArtifactId: AuthArtifactIdSchema, | 24 | authArtifactId: AuthArtifactIdSchema, |
| 22 | workspaceId: WorkspaceIdSchema, | 25 | scopeId: ScopeIdSchema, |
| 23 | sourceId: SourceIdSchema, | 26 | sourceId: SourceIdSchema, |
| 24 | actorAccountId: Schema.NullOr(AccountIdSchema), | 27 | actorScopeId: Schema.NullOr(ScopeIdSchema), |
| 25 | slot: AuthArtifactSlotSchema, | 28 | slot: AuthArtifactSlotSchema, |
| 26 | placementsTemplateJson: Schema.String, | 29 | placementsTemplateJson: Schema.String, |
| 27 | expiresAt: Schema.NullOr(TimestampMsSchema), | 30 | expiresAt: Schema.NullOr(TimestampMsSchema), |
| @@ -1,6 +1,10 @@ | |||
| 1 | import { Schema } from "effect"; | 1 | import { |
| 2 | Schema, | ||
| 3 | } from "effect"; | ||
| 2 | 4 | ||
| 3 | import { TimestampMsSchema } from "../common"; | 5 | import { |
| 6 | TimestampMsSchema, | ||
| 7 | } from "../common"; | ||
| 4 | 8 | ||
| 5 | export const StoredCodeMigrationRecordSchema = Schema.Struct({ | 9 | export const StoredCodeMigrationRecordSchema = Schema.Struct({ |
| 6 | id: Schema.String, | 10 | id: Schema.String, |
| @@ -1,12 +1,15 @@ | |||
| 1 | import { Schema } from "effect"; | 1 | import { |
| 2 | Schema, | ||
| 3 | } from "effect"; | ||
| 2 | 4 | ||
| 3 | import { TimestampMsSchema } from "../common"; | ||
| 4 | import { | 5 | import { |
| 5 | AccountIdSchema, | 6 | TimestampMsSchema, |
| 7 | } from "../common"; | ||
| 8 | import { | ||
| 6 | ExecutionIdSchema, | 9 | ExecutionIdSchema, |
| 7 | ExecutionInteractionIdSchema, | 10 | ExecutionInteractionIdSchema, |
| 8 | ExecutionStepIdSchema, | 11 | ExecutionStepIdSchema, |
| 9 | WorkspaceIdSchema, | 12 | ScopeIdSchema, |
| 10 | } from "../ids"; | 13 | } from "../ids"; |
| 11 | 14 | ||
| 12 | export const ExecutionStatusSchema = Schema.Literal( | 15 | export const ExecutionStatusSchema = Schema.Literal( |
| @@ -20,8 +23,8 @@ export const ExecutionStatusSchema = Schema.Literal( · 7 unmodified lines | |||
| 20 | 23 | ||
| 21 | export const ExecutionSchema = Schema.Struct({ | 24 | export const ExecutionSchema = Schema.Struct({ |
| 22 | id: ExecutionIdSchema, | 25 | id: ExecutionIdSchema, |
| 23 | workspaceId: WorkspaceIdSchema, | 26 | scopeId: ScopeIdSchema, |
| 24 | createdByAccountId: AccountIdSchema, | 27 | createdByScopeId: ScopeIdSchema, |
| 25 | status: ExecutionStatusSchema, | 28 | status: ExecutionStatusSchema, |
| 26 | code: Schema.String, | 29 | code: Schema.String, |
| 27 | resultJson: Schema.NullOr(Schema.String), | 30 | resultJson: Schema.NullOr(Schema.String), |
| @@ -1,6 +1,10 @@ | |||
| 1 | import { Schema } from "effect"; | 1 | import { |
| 2 | Schema, | ||
| 3 | } from "effect"; | ||
| 2 | 4 | ||
| 3 | import { localConfigurableSourceAdapters } from "../../runtime/sources/source-adapters"; | 5 | import { |
| 6 | localConfigurableSourceAdapters, | ||
| 7 | } from "../../runtime/sources/source-adapters"; | ||
| 4 | 8 | ||
| 5 | export const LocalExecutorRuntimeSchema = Schema.Literal( | 9 | export const LocalExecutorRuntimeSchema = Schema.Literal( |
| 6 | "quickjs", | 10 | "quickjs", |
| @@ -1,13 +1,13 @@ | |||
| 1 | import * as Schema from "effect/Schema"; | 1 | import * as Schema from "effect/Schema"; |
| 2 | 2 | ||
| 3 | import { | 3 | import { |
| 4 | AccountIdSchema, | 4 | ScopeIdSchema, |
| 5 | WorkspaceIdSchema, | ||
| 6 | } from "../ids"; | 5 | } from "../ids"; |
| 7 | 6 | ||
| 8 | export const LocalInstallationSchema = Schema.Struct({ | 7 | export const LocalInstallationSchema = Schema.Struct({ |
| 9 | accountId: AccountIdSchema, | 8 | scopeId: ScopeIdSchema, |
| 10 | workspaceId: WorkspaceIdSchema, | 9 | actorScopeId: ScopeIdSchema, |
| 10 | resolutionScopeIds: Schema.Array(ScopeIdSchema), | ||
| 11 | }); | 11 | }); |
| 12 | 12 | ||
| 13 | export const LocalInstallationInsertSchema = LocalInstallationSchema; | 13 | export const LocalInstallationInsertSchema = LocalInstallationSchema; |
| @@ -1,28 +1,35 @@ | |||
| 1 | import { Schema } from "effect"; | 1 | import { |
| 2 | Schema, | ||
| 3 | } from "effect"; | ||
| 2 | 4 | ||
| 3 | import { TimestampMsSchema } from "../common"; | 5 | import { |
| 4 | import { PolicyIdSchema, WorkspaceIdSchema } from "../ids"; | 6 | TimestampMsSchema, |
| 7 | } from "../common"; | ||
| 8 | import { | ||
| 9 | PolicyIdSchema, | ||
| 10 | ScopeIdSchema, | ||
| 11 | } from "../ids"; | ||
| 5 | 12 | ||
| 6 | export const LocalWorkspacePolicyEffectSchema = Schema.Literal("allow", "deny"); | 13 | export const LocalScopePolicyEffectSchema = Schema.Literal("allow", "deny"); |
| 7 | export const LocalWorkspacePolicyApprovalModeSchema = Schema.Literal("auto", "required"); | 14 | export const LocalScopePolicyApprovalModeSchema = Schema.Literal("auto", "required"); |
| 8 | 15 | ||
| 9 | export const LocalWorkspacePolicySchema = Schema.Struct({ | 16 | export const LocalScopePolicySchema = Schema.Struct({ |
| 10 | id: PolicyIdSchema, | 17 | id: PolicyIdSchema, |
| 11 | key: Schema.String, | 18 | key: Schema.String, |
| 12 | workspaceId: WorkspaceIdSchema, | 19 | scopeId: ScopeIdSchema, |
| 13 | resourcePattern: Schema.String, | 20 | resourcePattern: Schema.String, |
| 14 | effect: LocalWorkspacePolicyEffectSchema, | 21 | effect: LocalScopePolicyEffectSchema, |
| 15 | approvalMode: LocalWorkspacePolicyApprovalModeSchema, | 22 | approvalMode: LocalScopePolicyApprovalModeSchema, |
| 16 | priority: Schema.Number, | 23 | priority: Schema.Number, |
| 17 | enabled: Schema.Boolean, | 24 | enabled: Schema.Boolean, |
| 18 | createdAt: TimestampMsSchema, | 25 | createdAt: TimestampMsSchema, |
| 19 | updatedAt: TimestampMsSchema, | 26 | updatedAt: TimestampMsSchema, |
| 20 | }); | 27 | }); |
| 21 | 28 | ||
| 22 | export const LocalWorkspacePolicyInsertSchema = LocalWorkspacePolicySchema; | 29 | export const LocalScopePolicyInsertSchema = LocalScopePolicySchema; |
| 23 | export const LocalWorkspacePolicyUpdateSchema = Schema.partial(LocalWorkspacePolicySchema); | 30 | export const LocalScopePolicyUpdateSchema = Schema.partial(LocalScopePolicySchema); |
| 24 | 31 | ||
| 25 | export type LocalWorkspacePolicyEffect = typeof LocalWorkspacePolicyEffectSchema.Type; | 32 | export type LocalScopePolicyEffect = typeof LocalScopePolicyEffectSchema.Type; |
| 26 | export type LocalWorkspacePolicyApprovalMode = | 33 | export type LocalScopePolicyApprovalMode = |
| 27 | typeof LocalWorkspacePolicyApprovalModeSchema.Type; | 34 | typeof LocalScopePolicyApprovalModeSchema.Type; |
| 28 | export type LocalWorkspacePolicy = typeof LocalWorkspacePolicySchema.Type; | 35 | export type LocalScopePolicy = typeof LocalScopePolicySchema.Type; |
| @@ -1,11 +1,14 @@ | |||
| 1 | import { Schema } from "effect"; | 1 | import { |
| 2 | Schema, | ||
| 3 | } from "effect"; | ||
| 2 | 4 | ||
| 3 | import { TimestampMsSchema } from "../common"; | ||
| 4 | import { | 5 | import { |
| 5 | AccountIdSchema, | 6 | TimestampMsSchema, |
| 7 | } from "../common"; | ||
| 8 | import { | ||
| 9 | ScopeIdSchema, | ||
| 6 | ProviderAuthGrantIdSchema, | 10 | ProviderAuthGrantIdSchema, |
| 7 | WorkspaceIdSchema, | 11 | ScopeOauthClientIdSchema, |
| 8 | WorkspaceOauthClientIdSchema, | ||
| 9 | } from "../ids"; | 12 | } from "../ids"; |
| 10 | 13 | ||
| 11 | import { | 14 | import { |
| @@ -15,10 +18,10 @@ import { · 3 unmodified lines | |||
| 15 | 18 | ||
| 16 | export const ProviderAuthGrantSchema = Schema.Struct({ | 19 | export const ProviderAuthGrantSchema = Schema.Struct({ |
| 17 | id: ProviderAuthGrantIdSchema, | 20 | id: ProviderAuthGrantIdSchema, |
| 18 | workspaceId: WorkspaceIdSchema, | 21 | scopeId: ScopeIdSchema, |
| 19 | actorAccountId: Schema.NullOr(AccountIdSchema), | 22 | actorScopeId: Schema.NullOr(ScopeIdSchema), |
| 20 | providerKey: Schema.String, | 23 | providerKey: Schema.String, |
| 21 | oauthClientId: WorkspaceOauthClientIdSchema, | 24 | oauthClientId: ScopeOauthClientIdSchema, |
| 22 | tokenEndpoint: Schema.String, | 25 | tokenEndpoint: Schema.String, |
| 23 | clientAuthentication: OAuth2ClientAuthenticationMethodSchema, | 26 | clientAuthentication: OAuth2ClientAuthenticationMethodSchema, |
| 24 | headerName: Schema.String, | 27 | headerName: Schema.String, |
| @@ -1,14 +1,18 @@ | |||
| 1 | import { Schema } from "effect"; | 1 | import { |
| 2 | Schema, | ||
| 3 | } from "effect"; | ||
| 2 | 4 | ||
| 3 | import { TimestampMsSchema } from "../common"; | ||
| 4 | import { | 5 | import { |
| 5 | WorkspaceIdSchema, | 6 | TimestampMsSchema, |
| 6 | WorkspaceOauthClientIdSchema, | 7 | } from "../common"; |
| 8 | import { | ||
| 9 | ScopeIdSchema, | ||
| 10 | ScopeOauthClientIdSchema, | ||
| 7 | } from "../ids"; | 11 | } from "../ids"; |
| 8 | 12 | ||
| 9 | export const WorkspaceOauthClientSchema = Schema.Struct({ | 13 | export const ScopeOauthClientSchema = Schema.Struct({ |
| 10 | id: WorkspaceOauthClientIdSchema, | 14 | id: ScopeOauthClientIdSchema, |
| 11 | workspaceId: WorkspaceIdSchema, | 15 | scopeId: ScopeIdSchema, |
| 12 | providerKey: Schema.String, | 16 | providerKey: Schema.String, |
| 13 | label: Schema.NullOr(Schema.String), | 17 | label: Schema.NullOr(Schema.String), |
| 14 | clientId: Schema.String, | 18 | clientId: Schema.String, |
| @@ -19,4 +23,4 @@ export const WorkspaceOauthClientSchema = Schema.Struct({ · 4 unmodified lines | |||
| 19 | updatedAt: TimestampMsSchema, | 23 | updatedAt: TimestampMsSchema, |
| 20 | }); | 24 | }); |
| 21 | 25 | ||
| 22 | export type WorkspaceOauthClient = typeof WorkspaceOauthClientSchema.Type; | 26 | export type ScopeOauthClient = typeof ScopeOauthClientSchema.Type; |
| @@ -1,7 +1,13 @@ | |||
| 1 | import { Schema } from "effect"; | 1 | import { |
| 2 | Schema, | ||
| 3 | } from "effect"; | ||
| 2 | 4 | ||
| 3 | import { TimestampMsSchema } from "../common"; | 5 | import { |
| 4 | import { SecretMaterialIdSchema } from "../ids"; | 6 | TimestampMsSchema, |
| 7 | } from "../common"; | ||
| 8 | import { | ||
| 9 | SecretMaterialIdSchema, | ||
| 10 | } from "../ids"; | ||
| 5 | 11 | ||
| 6 | export const SecretMaterialPurposeSchema = Schema.Literal( | 12 | export const SecretMaterialPurposeSchema = Schema.Literal( |
| 7 | "auth_material", | 13 | "auth_material", |
| @@ -1,14 +1,17 @@ | |||
| 1 | import { Schema } from "effect"; | 1 | import { |
| 2 | Schema, | ||
| 3 | } from "effect"; | ||
| 2 | 4 | ||
| 3 | import { TimestampMsSchema } from "../common"; | ||
| 4 | import { | 5 | import { |
| 5 | AccountIdSchema, | 6 | TimestampMsSchema, |
| 7 | } from "../common"; | ||
| 8 | import { | ||
| 9 | ScopeIdSchema, | ||
| 6 | ExecutionIdSchema, | 10 | ExecutionIdSchema, |
| 7 | ExecutionInteractionIdSchema, | 11 | ExecutionInteractionIdSchema, |
| 8 | SourceIdSchema, | 12 | SourceIdSchema, |
| 9 | SourceAuthSessionIdSchema, | 13 | SourceAuthSessionIdSchema, |
| 10 | WorkspaceOauthClientIdSchema, | 14 | ScopeOauthClientIdSchema, |
| 11 | WorkspaceIdSchema, | ||
| 12 | } from "../ids"; | 15 | } from "../ids"; |
| 13 | import { | 16 | import { |
| 14 | CredentialSlotSchema, | 17 | CredentialSlotSchema, |
| @@ -109,7 +112,7 @@ export const ProviderOauthBatchSourceAuthSessionDataSchema = Schema.Struct({ · 94 unmodified lines | |||
| 109 | authorizationEndpoint: Schema.String, | 112 | authorizationEndpoint: Schema.String, |
| 110 | tokenEndpoint: Schema.String, | 113 | tokenEndpoint: Schema.String, |
| 111 | redirectUri: Schema.String, | 114 | redirectUri: Schema.String, |
| 112 | oauthClientId: WorkspaceOauthClientIdSchema, | 115 | oauthClientId: ScopeOauthClientIdSchema, |
| 113 | clientAuthentication: OAuth2ClientAuthenticationMethodSchema, | 116 | clientAuthentication: OAuth2ClientAuthenticationMethodSchema, |
| 114 | scopes: Schema.Array(Schema.String), | 117 | scopes: Schema.Array(Schema.String), |
| 115 | headerName: Schema.String, | 118 | headerName: Schema.String, |
| @@ -129,9 +132,9 @@ export const ProviderOauthBatchSourceAuthSessionDataJsonSchema = Schema.parseJso · 13 unmodified lines | |||
| 129 | 132 | ||
| 130 | export const SourceAuthSessionSchema = Schema.Struct({ | 133 | export const SourceAuthSessionSchema = Schema.Struct({ |
| 131 | id: SourceAuthSessionIdSchema, | 134 | id: SourceAuthSessionIdSchema, |
| 132 | workspaceId: WorkspaceIdSchema, | 135 | scopeId: ScopeIdSchema, |
| 133 | sourceId: SourceIdSchema, | 136 | sourceId: SourceIdSchema, |
| 134 | actorAccountId: Schema.NullOr(AccountIdSchema), | 137 | actorScopeId: Schema.NullOr(ScopeIdSchema), |
| 135 | credentialSlot: CredentialSlotSchema, | 138 | credentialSlot: CredentialSlotSchema, |
| 136 | executionId: Schema.NullOr(ExecutionIdSchema), | 139 | executionId: Schema.NullOr(ExecutionIdSchema), |
| 137 | interactionId: Schema.NullOr(ExecutionInteractionIdSchema), | 140 | interactionId: Schema.NullOr(ExecutionInteractionIdSchema), |
| @@ -1,6 +1,10 @@ | |||
| 1 | import { Schema } from "effect"; | 1 | import { |
| 2 | Schema, | ||
| 3 | } from "effect"; | ||
| 2 | 4 | ||
| 3 | import { TimestampMsSchema } from "../common"; | 5 | import { |
| 6 | TimestampMsSchema, | ||
| 7 | } from "../common"; | ||
| 4 | import { | 8 | import { |
| 5 | SourceCatalogIdSchema, | 9 | SourceCatalogIdSchema, |
| 6 | SourceCatalogRevisionIdSchema, | 10 | SourceCatalogRevisionIdSchema, |
| @@ -15,7 +19,7 @@ export const SourceCatalogAdapterKeySchema = Schema.String; · 8 unmodified lines | |||
| 15 | 19 | ||
| 16 | export const SourceCatalogVisibilitySchema = Schema.Literal( | 20 | export const SourceCatalogVisibilitySchema = Schema.Literal( |
| 17 | "private", | 21 | "private", |
| 18 | "workspace", | 22 | "scope", |
| 19 | "organization", | 23 | "organization", |
| 20 | "public", | 24 | "public", |
| 21 | ); | 25 | ); |
| @@ -1,6 +1,10 @@ | |||
| 1 | import { Schema } from "effect"; | 1 | import { |
| 2 | Schema, | ||
| 3 | } from "effect"; | ||
| 2 | 4 | ||
| 3 | import { SourceSchema } from "./source"; | 5 | import { |
| 6 | SourceSchema, | ||
| 7 | } from "./source"; | ||
| 4 | 8 | ||
| 5 | export const SourceInspectionPipelineKindSchema = Schema.Literal("ir"); | 9 | export const SourceInspectionPipelineKindSchema = Schema.Literal("ir"); |
| 6 | 10 | ||
| @@ -1,31 +1,35 @@ | |||
| 1 | import { Schema } from "effect"; | 1 | import { |
| 2 | Schema, | ||
| 3 | } from "effect"; | ||
| 2 | export { | 4 | export { |
| 3 | SourceOauthClientInputSchema, | 5 | SourceOauthClientInputSchema, |
| 4 | WorkspaceSourceOauthClientRedirectModeSchema, | 6 | ScopedSourceOauthClientRedirectModeSchema, |
| 5 | } from "@executor/source-core"; | 7 | } from "@executor/source-core"; |
| 6 | import { | 8 | import { |
| 7 | SourceOauthClientInputSchema, | 9 | SourceOauthClientInputSchema, |
| 8 | WorkspaceSourceOauthClientRedirectModeSchema, | 10 | ScopedSourceOauthClientRedirectModeSchema, |
| 9 | } from "@executor/source-core"; | 11 | } from "@executor/source-core"; |
| 10 | 12 | ||
| 11 | import { TimestampMsSchema } from "../common"; | 13 | import { |
| 14 | TimestampMsSchema, | ||
| 15 | } from "../common"; | ||
| 12 | import { | 16 | import { |
| 13 | SourceIdSchema, | 17 | SourceIdSchema, |
| 14 | WorkspaceIdSchema, | 18 | ScopeIdSchema, |
| 15 | WorkspaceSourceOauthClientIdSchema, | 19 | ScopedSourceOauthClientIdSchema, |
| 16 | } from "../ids"; | 20 | } from "../ids"; |
| 17 | 21 | ||
| 18 | export const WorkspaceSourceOauthClientMetadataSchema = Schema.Struct({ | 22 | export const ScopedSourceOauthClientMetadataSchema = Schema.Struct({ |
| 19 | redirectMode: Schema.optional(WorkspaceSourceOauthClientRedirectModeSchema), | 23 | redirectMode: Schema.optional(ScopedSourceOauthClientRedirectModeSchema), |
| 20 | }); | 24 | }); |
| 21 | 25 | ||
| 22 | export const WorkspaceSourceOauthClientMetadataJsonSchema = Schema.parseJson( | 26 | export const ScopedSourceOauthClientMetadataJsonSchema = Schema.parseJson( |
| 23 | WorkspaceSourceOauthClientMetadataSchema, | 27 | ScopedSourceOauthClientMetadataSchema, |
| 24 | ); | 28 | ); |
| 25 | 29 | ||
| 26 | export const WorkspaceSourceOauthClientSchema = Schema.Struct({ | 30 | export const ScopedSourceOauthClientSchema = Schema.Struct({ |
| 27 | id: WorkspaceSourceOauthClientIdSchema, | 31 | id: ScopedSourceOauthClientIdSchema, |
| 28 | workspaceId: WorkspaceIdSchema, | 32 | scopeId: ScopeIdSchema, |
| 29 | sourceId: SourceIdSchema, | 33 | sourceId: SourceIdSchema, |
| 30 | providerKey: Schema.String, | 34 | providerKey: Schema.String, |
| 31 | clientId: Schema.String, | 35 | clientId: Schema.String, |
| @@ -36,9 +40,9 @@ export const WorkspaceSourceOauthClientSchema = Schema.Struct({ · 4 unmodified lines | |||
| 36 | updatedAt: TimestampMsSchema, | 40 | updatedAt: TimestampMsSchema, |
| 37 | }); | 41 | }); |
| 38 | 42 | ||
| 39 | export type WorkspaceSourceOauthClient = typeof WorkspaceSourceOauthClientSchema.Type; | 43 | export type ScopedSourceOauthClient = typeof ScopedSourceOauthClientSchema.Type; |
| 40 | export type WorkspaceSourceOauthClientRedirectMode = | 44 | export type ScopedSourceOauthClientRedirectMode = |
| 41 | typeof WorkspaceSourceOauthClientRedirectModeSchema.Type; | 45 | typeof ScopedSourceOauthClientRedirectModeSchema.Type; |
| 42 | export type WorkspaceSourceOauthClientMetadata = | 46 | export type ScopedSourceOauthClientMetadata = |
| 43 | typeof WorkspaceSourceOauthClientMetadataSchema.Type; | 47 | typeof ScopedSourceOauthClientMetadataSchema.Type; |
| 44 | export type SourceOauthClientInput = typeof SourceOauthClientInputSchema.Type; | 48 | export type SourceOauthClientInput = typeof SourceOauthClientInputSchema.Type; |
| @@ -1,4 +1,6 @@ | |||
| 1 | import { Schema } from "effect"; | 1 | import { |
| 2 | Schema, | ||
| 3 | } from "effect"; | ||
| 2 | export { | 4 | export { |
| 3 | SourceImportAuthPolicySchema, | 5 | SourceImportAuthPolicySchema, |
| 4 | SourceTransportSchema, | 6 | SourceTransportSchema, |
| @@ -10,16 +12,22 @@ import { · 5 unmodified lines | |||
| 10 | StringMapSchema, | 12 | StringMapSchema, |
| 11 | } from "@executor/source-core"; | 13 | } from "@executor/source-core"; |
| 12 | 14 | ||
| 13 | import { TimestampMsSchema } from "../common"; | 15 | import { |
| 16 | TimestampMsSchema, | ||
| 17 | } from "../common"; | ||
| 14 | import { | 18 | import { |
| 15 | ProviderAuthGrantIdSchema, | 19 | ProviderAuthGrantIdSchema, |
| 16 | SourceIdSchema, | 20 | SourceIdSchema, |
| 17 | SourceCatalogIdSchema, | 21 | SourceCatalogIdSchema, |
| 18 | SourceCatalogRevisionIdSchema, | 22 | SourceCatalogRevisionIdSchema, |
| 19 | WorkspaceIdSchema, | 23 | ScopeIdSchema, |
| 20 | } from "../ids"; | 24 | } from "../ids"; |
| 21 | import { SecretRefSchema } from "./auth-artifact"; | 25 | import { |
| 22 | import { JsonObjectSchema } from "./source-auth-session"; | 26 | SecretRefSchema, |
| 27 | } from "./auth-artifact"; | ||
| 28 | import { | ||
| 29 | JsonObjectSchema, | ||
| 30 | } from "./source-auth-session"; | ||
| 23 | 31 | ||
| 24 | export const SourceKindSchema = Schema.String; | 32 | export const SourceKindSchema = Schema.String; |
| 25 | 33 | ||
| @@ -91,7 +99,7 @@ export const SourceBindingSchema = Schema.Struct({ · 65 unmodified lines | |||
| 91 | }); | 99 | }); |
| 92 | 100 | ||
| 93 | const SourceStorageRowSchema = Schema.Struct({ | 101 | const SourceStorageRowSchema = Schema.Struct({ |
| 94 | workspaceId: WorkspaceIdSchema, | 102 | scopeId: ScopeIdSchema, |
| 95 | sourceId: SourceIdSchema, | 103 | sourceId: SourceIdSchema, |
| 96 | catalogId: SourceCatalogIdSchema, | 104 | catalogId: SourceCatalogIdSchema, |
| 97 | catalogRevisionId: SourceCatalogRevisionIdSchema, | 105 | catalogRevisionId: SourceCatalogRevisionIdSchema, |
| @@ -113,7 +121,7 @@ export const StoredSourceRecordSchema = Schema.transform( · 15 unmodified lines | |||
| 113 | SourceStorageRowSchema, | 121 | SourceStorageRowSchema, |
| 114 | Schema.Struct({ | 122 | Schema.Struct({ |
| 115 | id: SourceIdSchema, | 123 | id: SourceIdSchema, |
| 116 | workspaceId: WorkspaceIdSchema, | 124 | scopeId: ScopeIdSchema, |
| 117 | catalogId: SourceCatalogIdSchema, | 125 | catalogId: SourceCatalogIdSchema, |
| 118 | catalogRevisionId: SourceCatalogRevisionIdSchema, | 126 | catalogRevisionId: SourceCatalogRevisionIdSchema, |
| 119 | name: Schema.String, | 127 | name: Schema.String, |
| @@ -133,7 +141,7 @@ export const StoredSourceRecordSchema = Schema.transform( · 13 unmodified lines | |||
| 133 | strict: false, | 141 | strict: false, |
| 134 | decode: (row) => ({ | 142 | decode: (row) => ({ |
| 135 | id: row.sourceId, | 143 | id: row.sourceId, |
| 136 | workspaceId: row.workspaceId, | 144 | scopeId: row.scopeId, |
| 137 | catalogId: row.catalogId, | 145 | catalogId: row.catalogId, |
| 138 | catalogRevisionId: row.catalogRevisionId, | 146 | catalogRevisionId: row.catalogRevisionId, |
| 139 | name: row.name, | 147 | name: row.name, |
| @@ -150,7 +158,7 @@ export const StoredSourceRecordSchema = Schema.transform( · 10 unmodified lines | |||
| 150 | updatedAt: row.updatedAt, | 158 | updatedAt: row.updatedAt, |
| 151 | }), | 159 | }), |
| 152 | encode: (source) => ({ | 160 | encode: (source) => ({ |
| 153 | workspaceId: source.workspaceId, | 161 | scopeId: source.scopeId, |
| 154 | sourceId: source.id, | 162 | sourceId: source.id, |
| 155 | catalogId: source.catalogId, | 163 | catalogId: source.catalogId, |
| 156 | catalogRevisionId: source.catalogRevisionId, | 164 | catalogRevisionId: source.catalogRevisionId, |
| @@ -172,7 +180,7 @@ export const StoredSourceRecordSchema = Schema.transform( · 15 unmodified lines | |||
| 172 | 180 | ||
| 173 | export const SourceSchema = Schema.Struct({ | 181 | export const SourceSchema = Schema.Struct({ |
| 174 | id: SourceIdSchema, | 182 | id: SourceIdSchema, |
| 175 | workspaceId: WorkspaceIdSchema, | 183 | scopeId: ScopeIdSchema, |
| 176 | name: Schema.String, | 184 | name: Schema.String, |
| 177 | kind: SourceKindSchema, | 185 | kind: SourceKindSchema, |
| 178 | endpoint: Schema.String, | 186 | endpoint: Schema.String, |
| @@ -1,4 +1,8 @@ | |||
| 1 | import { describe, expect, it } from "@effect/vitest"; | 1 | import { |
| 2 | describe, | ||
| 3 | expect, | ||
| 4 | it, | ||
| 5 | } from "@effect/vitest"; | ||
| 2 | import * as Either from "effect/Either"; | 6 | import * as Either from "effect/Either"; |
| 3 | import * as Schema from "effect/Schema"; | 7 | import * as Schema from "effect/Schema"; |
| 4 | 8 | ||
| @@ -0,0 +1,17 @@ | |||
| 1 | import type { | ||
| 2 | ScopeId, | ||
| 3 | } from "./schema"; | ||
| 4 | |||
| 5 | export type ExecutorScopeDescriptor = { | ||
| 6 | scopeName: string; | ||
| 7 | scopeRoot?: string | null; | ||
| 8 | actorScopeId?: ScopeId | null; | ||
| 9 | resolutionScopeIds?: ReadonlyArray<ScopeId>; | ||
| 10 | metadata?: Readonly<Record<string, unknown>>; | ||
| 11 | }; | ||
| 12 | |||
| 13 | export type ExecutorScopeContext = ExecutorScopeDescriptor & { | ||
| 14 | scopeId: ScopeId; | ||
| 15 | actorScopeId: ScopeId | null; | ||
| 16 | resolutionScopeIds: ReadonlyArray<ScopeId>; | ||
| 17 | }; | ||
| @@ -12,9 +12,9 @@ import { · 11 unmodified lines | |||
| 12 | SourceSchema, | 12 | SourceSchema, |
| 13 | SourceStatusSchema, | 13 | SourceStatusSchema, |
| 14 | SourceOauthClientInputSchema, | 14 | SourceOauthClientInputSchema, |
| 15 | WorkspaceIdSchema, | 15 | ScopeIdSchema, |
| 16 | WorkspaceOauthClientIdSchema, | 16 | ScopeOauthClientIdSchema, |
| 17 | WorkspaceOauthClientSchema, | 17 | ScopeOauthClientSchema, |
| 18 | } from "../schema"; | 18 | } from "../schema"; |
| 19 | import { | 19 | import { |
| 20 | ConnectSourcePayloadSchema, | 20 | ConnectSourcePayloadSchema, |
| @@ -84,20 +84,20 @@ export const CredentialOauthCompleteUrlParamsSchema = Schema.Struct({ · 63 unmodified lines | |||
| 84 | error_description: Schema.optional(Schema.String), | 84 | error_description: Schema.optional(Schema.String), |
| 85 | }); | 85 | }); |
| 86 | 86 | ||
| 87 | export const WorkspaceOauthClientQuerySchema = Schema.Struct({ | 87 | export const ScopeOauthClientQuerySchema = Schema.Struct({ |
| 88 | providerKey: Schema.String, | 88 | providerKey: Schema.String, |
| 89 | }); | 89 | }); |
| 90 | 90 | ||
| 91 | export const CreateWorkspaceOauthClientPayloadSchema = Schema.Struct({ | 91 | export const CreateScopeOauthClientPayloadSchema = Schema.Struct({ |
| 92 | providerKey: Schema.String, | 92 | providerKey: Schema.String, |
| 93 | label: Schema.optional(Schema.NullOr(Schema.String)), | 93 | label: Schema.optional(Schema.NullOr(Schema.String)), |
| 94 | oauthClient: SourceOauthClientInputSchema, | 94 | oauthClient: SourceOauthClientInputSchema, |
| 95 | }); | 95 | }); |
| 96 | 96 | ||
| 97 | export type CreateWorkspaceOauthClientPayload = | 97 | export type CreateScopeOauthClientPayload = |
| 98 | typeof CreateWorkspaceOauthClientPayloadSchema.Type; | 98 | typeof CreateScopeOauthClientPayloadSchema.Type; |
| 99 | 99 | ||
| 100 | export const oauthClientIdParam = WorkspaceOauthClientIdSchema; | 100 | export const oauthClientIdParam = ScopeOauthClientIdSchema; |
| 101 | export const grantIdParam = ProviderAuthGrantIdSchema; | 101 | export const grantIdParam = ProviderAuthGrantIdSchema; |
| 102 | 102 | ||
| 103 | const ConnectGoogleDiscoveryBatchSourceSchema = Schema.Struct({ | 103 | const ConnectGoogleDiscoveryBatchSourceSchema = Schema.Struct({ |
| @@ -110,7 +110,7 @@ const ConnectGoogleDiscoveryBatchSourceSchema = Schema.Struct({ · 6 unmodified lines | |||
| 110 | }); | 110 | }); |
| 111 | 111 | ||
| 112 | export const ConnectSourceBatchPayloadSchema = Schema.Struct({ | 112 | export const ConnectSourceBatchPayloadSchema = Schema.Struct({ |
| 113 | workspaceOauthClientId: WorkspaceOauthClientIdSchema, | 113 | scopeOauthClientId: ScopeOauthClientIdSchema, |
| 114 | sources: Schema.Array(ConnectGoogleDiscoveryBatchSourceSchema), | 114 | sources: Schema.Array(ConnectGoogleDiscoveryBatchSourceSchema), |
| 115 | }); | 115 | }); |
| 116 | 116 | ||
| @@ -165,6 +165,6 @@ export { · 48 unmodified lines | |||
| 165 | ConnectSourcePayloadSchema, | 165 | ConnectSourcePayloadSchema, |
| 166 | type ConnectSourcePayload, | 166 | type ConnectSourcePayload, |
| 167 | SourceDiscoveryResultSchema, | 167 | SourceDiscoveryResultSchema, |
| 168 | WorkspaceIdSchema, | 168 | ScopeIdSchema, |
| 169 | WorkspaceOauthClientSchema, | 169 | ScopeOauthClientSchema, |
| 170 | }; | 170 | }; |
| @@ -9,7 +9,9 @@ import { · 8 unmodified lines | |||
| 9 | type SourceDiscoveryResult, | 9 | type SourceDiscoveryResult, |
| 10 | } from "@executor/source-core"; | 10 | } from "@executor/source-core"; |
| 11 | 11 | ||
| 12 | import { builtInSourceAdapters } from "../runtime/sources/source-adapters"; | 12 | import { |
| 13 | builtInSourceAdapters, | ||
| 14 | } from "../runtime/sources/source-adapters"; | ||
| 13 | 15 | ||
| 14 | type DiscoverableSourceAdapter = SourceAdapter & { | 16 | type DiscoverableSourceAdapter = SourceAdapter & { |
| 15 | detectSource: NonNullable<SourceAdapter["detectSource"]>; | 17 | detectSource: NonNullable<SourceAdapter["detectSource"]>; |
| @@ -8,7 +8,7 @@ import type { · 7 unmodified lines | |||
| 8 | SourceInspectionToolDetail, | 8 | SourceInspectionToolDetail, |
| 9 | SourceInspectionToolListItem, | 9 | SourceInspectionToolListItem, |
| 10 | SourceInspectionToolSummary, | 10 | SourceInspectionToolSummary, |
| 11 | WorkspaceId, | 11 | ScopeId, |
| 12 | } from "../schema"; | 12 | } from "../schema"; |
| 13 | import { | 13 | import { |
| 14 | ControlPlaneNotFoundError, | 14 | ControlPlaneNotFoundError, |
| @@ -16,8 +16,12 @@ import { · 1 unmodified line | |||
| 16 | } from "../errors"; | 16 | } from "../errors"; |
| 17 | import * as Effect from "effect/Effect"; | 17 | import * as Effect from "effect/Effect"; |
| 18 | 18 | ||
| 19 | import { LocalSourceArtifactMissingError } from "../runtime/workspace-errors"; | 19 | import { |
| 20 | import { operationErrors } from "../runtime/policy/operation-errors"; | 20 | LocalSourceArtifactMissingError, |
| 21 | } from "../runtime/scope-errors"; | ||
| 22 | import { | ||
| 23 | operationErrors, | ||
| 24 | } from "../runtime/policy/operation-errors"; | ||
| 21 | import { | 25 | import { |
| 22 | buildLoadedSourceCatalogToolContract, | 26 | buildLoadedSourceCatalogToolContract, |
| 23 | expandCatalogToolByPath, | 27 | expandCatalogToolByPath, |
| @@ -25,7 +29,9 @@ import { · 1 unmodified line | |||
| 25 | loadSourceWithCatalog, | 29 | loadSourceWithCatalog, |
| 26 | type LoadedSourceCatalogTool, | 30 | type LoadedSourceCatalogTool, |
| 27 | } from "../runtime/catalog/source/runtime"; | 31 | } from "../runtime/catalog/source/runtime"; |
| 28 | import { RuntimeSourceStoreService } from "../runtime/sources/source-store"; | 32 | import { |
| 33 | RuntimeSourceStoreService, | ||
| 34 | } from "../runtime/sources/source-store"; | ||
| 29 | 35 | ||
| 30 | const sourceInspectOps = { | 36 | const sourceInspectOps = { |
| 31 | bundle: operationErrors("sources.inspect.bundle"), | 37 | bundle: operationErrors("sources.inspect.bundle"), |
| @@ -46,14 +52,14 @@ const canInspectSourceWithoutCatalog = (source: Source): boolean => · 14 unmodified lines | |||
| 46 | source.status === "auth_required"; | 52 | source.status === "auth_required"; |
| 47 | 53 | ||
| 48 | const loadSourceForMissingCatalog = (input: { | 54 | const loadSourceForMissingCatalog = (input: { |
| 49 | workspaceId: WorkspaceId; | 55 | scopeId: ScopeId; |
| 50 | sourceId: SourceId; | 56 | sourceId: SourceId; |
| 51 | cause: LocalSourceArtifactMissingError; | 57 | cause: LocalSourceArtifactMissingError; |
| 52 | }) => | 58 | }) => |
| 53 | Effect.gen(function* () { | 59 | Effect.gen(function* () { |
| 54 | const sourceStore = yield* RuntimeSourceStoreService; | 60 | const sourceStore = yield* RuntimeSourceStoreService; |
| 55 | const source = yield* sourceStore.loadSourceById({ | 61 | const source = yield* sourceStore.loadSourceById({ |
| 56 | workspaceId: input.workspaceId, | 62 | scopeId: input.scopeId, |
| 57 | sourceId: input.sourceId, | 63 | sourceId: input.sourceId, |
| 58 | }); | 64 | }); |
| 59 | 65 | ||
| @@ -65,11 +71,11 @@ const loadSourceForMissingCatalog = (input: { · 5 unmodified lines | |||
| 65 | }); | 71 | }); |
| 66 | 72 | ||
| 67 | const loadSourceCatalogOrEmpty = (input: { | 73 | const loadSourceCatalogOrEmpty = (input: { |
| 68 | workspaceId: WorkspaceId; | 74 | scopeId: ScopeId; |
| 69 | sourceId: SourceId; | 75 | sourceId: SourceId; |
| 70 | }) => | 76 | }) => |
| 71 | loadSourceWithCatalog({ | 77 | loadSourceWithCatalog({ |
| 72 | workspaceId: input.workspaceId, | 78 | scopeId: input.scopeId, |
| 73 | sourceId: input.sourceId, | 79 | sourceId: input.sourceId, |
| 74 | }).pipe( | 80 | }).pipe( |
| 75 | Effect.map((catalogEntry) => ({ | 81 | Effect.map((catalogEntry) => ({ |
| @@ -79,7 +85,7 @@ const loadSourceCatalogOrEmpty = (input: { · 3 unmodified lines | |||
| 79 | Effect.catchTag("LocalSourceArtifactMissingError", (cause) => | 85 | Effect.catchTag("LocalSourceArtifactMissingError", (cause) => |
| 80 | Effect.gen(function* () { | 86 | Effect.gen(function* () { |
| 81 | const source = yield* loadSourceForMissingCatalog({ | 87 | const source = yield* loadSourceForMissingCatalog({ |
| 82 | workspaceId: input.workspaceId, | 88 | scopeId: input.scopeId, |
| 83 | sourceId: input.sourceId, | 89 | sourceId: input.sourceId, |
| 84 | cause, | 90 | cause, |
| 85 | }); | 91 | }); |
| @@ -273,14 +279,14 @@ export const inspectionToolDetailFromTool = ( · 187 unmodified lines | |||
| 273 | }); | 279 | }); |
| 274 | 280 | ||
| 275 | const resolveSourceInspection = (input: { | 281 | const resolveSourceInspection = (input: { |
| 276 | workspaceId: WorkspaceId; | 282 | scopeId: ScopeId; |
| 277 | sourceId: SourceId; | 283 | sourceId: SourceId; |
| 278 | includeSchemas: boolean; | 284 | includeSchemas: boolean; |
| 279 | includeTypePreviews: boolean; | 285 | includeTypePreviews: boolean; |
| 280 | }) => | 286 | }) => |
| 281 | Effect.gen(function* () { | 287 | Effect.gen(function* () { |
| 282 | const loaded = yield* loadSourceCatalogOrEmpty({ | 288 | const loaded = yield* loadSourceCatalogOrEmpty({ |
| 283 | workspaceId: input.workspaceId, | 289 | scopeId: input.scopeId, |
| 284 | sourceId: input.sourceId, | 290 | sourceId: input.sourceId, |
| 285 | }); | 291 | }); |
| 286 | 292 | ||
| @@ -308,13 +314,13 @@ const resolveSourceInspection = (input: { · 21 unmodified lines | |||
| 308 | }); | 314 | }); |
| 309 | 315 | ||
| 310 | const resolveSourceInspectionTool = (input: { | 316 | const resolveSourceInspectionTool = (input: { |
| 311 | workspaceId: WorkspaceId; | 317 | scopeId: ScopeId; |
| 312 | sourceId: SourceId; | 318 | sourceId: SourceId; |
| 313 | toolPath: string; | 319 | toolPath: string; |
| 314 | }) => | 320 | }) => |
| 315 | Effect.gen(function* () { | 321 | Effect.gen(function* () { |
| 316 | const loaded = yield* loadSourceCatalogOrEmpty({ | 322 | const loaded = yield* loadSourceCatalogOrEmpty({ |
| 317 | workspaceId: input.workspaceId, | 323 | scopeId: input.scopeId, |
| 318 | sourceId: input.sourceId, | 324 | sourceId: input.sourceId, |
| 319 | }); | 325 | }); |
| 320 | 326 | ||
| @@ -425,7 +431,7 @@ const mapInspectionError = ( · 104 unmodified lines | |||
| 425 | }; | 431 | }; |
| 426 | 432 | ||
| 427 | export const getSourceInspection = (input: { | 433 | export const getSourceInspection = (input: { |
| 428 | workspaceId: WorkspaceId; | 434 | scopeId: ScopeId; |
| 429 | sourceId: SourceId; | 435 | sourceId: SourceId; |
| 430 | }) => | 436 | }) => |
| 431 | Effect.gen(function* () { | 437 | Effect.gen(function* () { |
| @@ -456,13 +462,13 @@ export const getSourceInspection = (input: { · 24 unmodified lines | |||
| 456 | ); | 462 | ); |
| 457 | 463 | ||
| 458 | export const getSourceInspectionToolDetail = (input: { | 464 | export const getSourceInspectionToolDetail = (input: { |
| 459 | workspaceId: WorkspaceId; | 465 | scopeId: ScopeId; |
| 460 | sourceId: SourceId; | 466 | sourceId: SourceId; |
| 461 | toolPath: string; | 467 | toolPath: string; |
| 462 | }) => | 468 | }) => |
| 463 | Effect.gen(function* () { | 469 | Effect.gen(function* () { |
| 464 | const inspection = yield* resolveSourceInspectionTool({ | 470 | const inspection = yield* resolveSourceInspectionTool({ |
| 465 | workspaceId: input.workspaceId, | 471 | scopeId: input.scopeId, |
| 466 | sourceId: input.sourceId, | 472 | sourceId: input.sourceId, |
| 467 | toolPath: input.toolPath, | 473 | toolPath: input.toolPath, |
| 468 | }); | 474 | }); |
| @@ -471,7 +477,7 @@ export const getSourceInspectionToolDetail = (input: { · 2 unmodified lines | |||
| 471 | if (!tool) { | 477 | if (!tool) { |
| 472 | return yield* sourceInspectOps.tool.notFound( | 478 | return yield* sourceInspectOps.tool.notFound( |
| 473 | "Tool not found", | 479 | "Tool not found", |
| 474 | `workspaceId=${input.workspaceId} sourceId=${input.sourceId} path=${input.toolPath}`, | 480 | `scopeId=${input.scopeId} sourceId=${input.sourceId} path=${input.toolPath}`, |
| 475 | ); | 481 | ); |
| 476 | } | 482 | } |
| 477 | 483 | ||
| @@ -487,13 +493,13 @@ export const getSourceInspectionToolDetail = (input: { · 9 unmodified lines | |||
| 487 | ); | 493 | ); |
| 488 | 494 | ||
| 489 | export const discoverSourceInspectionTools = (input: { | 495 | export const discoverSourceInspectionTools = (input: { |
| 490 | workspaceId: WorkspaceId; | 496 | scopeId: ScopeId; |
| 491 | sourceId: SourceId; | 497 | sourceId: SourceId; |
| 492 | payload: SourceInspectionDiscoverPayload; | 498 | payload: SourceInspectionDiscoverPayload; |
| 493 | }) => | 499 | }) => |
| 494 | Effect.gen(function* () { | 500 | Effect.gen(function* () { |
| 495 | const inspection = yield* resolveSourceInspection({ | 501 | const inspection = yield* resolveSourceInspection({ |
| 496 | workspaceId: input.workspaceId, | 502 | scopeId: input.scopeId, |
| 497 | sourceId: input.sourceId, | 503 | sourceId: input.sourceId, |
| 498 | includeSchemas: false, | 504 | includeSchemas: false, |
| 499 | includeTypePreviews: false, | 505 | includeTypePreviews: false, |
| @@ -3,11 +3,10 @@ import type { · 2 unmodified lines | |||
| 3 | UpdateSourcePayload, | 3 | UpdateSourcePayload, |
| 4 | } from "./contracts"; | 4 | } from "./contracts"; |
| 5 | import { | 5 | import { |
| 6 | type AccountId, | 6 | type ScopeId, |
| 7 | SourceIdSchema, | 7 | SourceIdSchema, |
| 8 | type Source, | 8 | type Source, |
| 9 | type SourceId, | 9 | type SourceId, |
| 10 | type WorkspaceId, | ||
| 11 | } from "../schema"; | 10 | } from "../schema"; |
| 12 | import * as Either from "effect/Either"; | 11 | import * as Either from "effect/Either"; |
| 13 | import * as Effect from "effect/Effect"; | 12 | import * as Effect from "effect/Effect"; |
| @@ -16,15 +15,25 @@ import { · 2 unmodified lines | |||
| 16 | createSourceFromPayload, | 15 | createSourceFromPayload, |
| 17 | updateSourceFromPayload, | 16 | updateSourceFromPayload, |
| 18 | } from "../runtime/sources/source-definitions"; | 17 | } from "../runtime/sources/source-definitions"; |
| 19 | import { getSourceAdapterForSource } from "../runtime/sources/source-adapters"; | 18 | import { |
| 20 | import { mapPersistenceError } from "../runtime/policy/operations-shared"; | 19 | getSourceAdapterForSource, |
| 21 | import { operationErrors } from "../runtime/policy/operation-errors"; | 20 | } from "../runtime/sources/source-adapters"; |
| 21 | import { | ||
| 22 | mapPersistenceError, | ||
| 23 | } from "../runtime/policy/operations-shared"; | ||
| 24 | import { | ||
| 25 | operationErrors, | ||
| 26 | } from "../runtime/policy/operation-errors"; | ||
| 22 | import { | 27 | import { |
| 23 | ExecutorStateStore, | 28 | ExecutorStateStore, |
| 24 | type ExecutorStateStoreShape, | 29 | type ExecutorStateStoreShape, |
| 25 | } from "../runtime/executor-state-store"; | 30 | } from "../runtime/executor-state-store"; |
| 26 | import { RuntimeSourceCatalogSyncService } from "../runtime/catalog/source/sync"; | 31 | import { |
| 27 | import { RuntimeSourceStoreService } from "../runtime/sources/source-store"; | 32 | RuntimeSourceCatalogSyncService, |
| 33 | } from "../runtime/catalog/source/sync"; | ||
| 34 | import { | ||
| 35 | RuntimeSourceStoreService, | ||
| 36 | } from "../runtime/sources/source-store"; | ||
| 28 | 37 | ||
| 29 | const sourceOps = { | 38 | const sourceOps = { |
| 30 | list: operationErrors("sources.list"), | 39 | list: operationErrors("sources.list"), |
| @@ -41,7 +50,7 @@ const syncArtifactsForSource = (input: { · 10 unmodified lines | |||
| 41 | store: ExecutorStateStoreShape; | 50 | store: ExecutorStateStoreShape; |
| 42 | sourceStore: Effect.Effect.Success<typeof RuntimeSourceStoreService>; | 51 | sourceStore: Effect.Effect.Success<typeof RuntimeSourceStoreService>; |
| 43 | source: Source; | 52 | source: Source; |
| 44 | actorAccountId: AccountId; | 53 | actorScopeId: ScopeId; |
| 45 | operation: typeof sourceOps.create | typeof sourceOps.update; | 54 | operation: typeof sourceOps.create | typeof sourceOps.update; |
| 46 | }) => | 55 | }) => |
| 47 | Effect.gen(function* () { | 56 | Effect.gen(function* () { |
| @@ -59,7 +68,7 @@ const syncArtifactsForSource = (input: { · 11 unmodified lines | |||
| 59 | const synced = yield* Effect.either( | 68 | const synced = yield* Effect.either( |
| 60 | catalogSyncService.sync({ | 69 | catalogSyncService.sync({ |
| 61 | source: sourceForSync, | 70 | source: sourceForSync, |
| 62 | actorAccountId: input.actorAccountId, | 71 | actorScopeId: input.actorScopeId, |
| 63 | }), | 72 | }), |
| 64 | ); | 73 | ); |
| 65 | 74 | ||
| @@ -82,7 +91,7 @@ const syncArtifactsForSource = (input: { · 16 unmodified lines | |||
| 82 | yield* mapPersistenceError( | 91 | yield* mapPersistenceError( |
| 83 | input.operation.child("source_connected"), | 92 | input.operation.child("source_connected"), |
| 84 | input.sourceStore.persistSource(connectedSource, { | 93 | input.sourceStore.persistSource(connectedSource, { |
| 85 | actorAccountId: input.actorAccountId, | 94 | actorScopeId: input.actorScopeId, |
| 86 | }), | 95 | }), |
| 87 | ); | 96 | ); |
| 88 | return connectedSource; | 97 | return connectedSource; |
| @@ -114,7 +123,7 @@ const syncArtifactsForSource = (input: { · 25 unmodified lines | |||
| 114 | yield* mapPersistenceError( | 123 | yield* mapPersistenceError( |
| 115 | input.operation.child("source_error"), | 124 | input.operation.child("source_error"), |
| 116 | input.sourceStore.persistSource(erroredSource, { | 125 | input.sourceStore.persistSource(erroredSource, { |
| 117 | actorAccountId: input.actorAccountId, | 126 | actorScopeId: input.actorScopeId, |
| 118 | }), | 127 | }), |
| 119 | ); | 128 | ); |
| 120 | } | 129 | } |
| @@ -128,16 +137,16 @@ const syncArtifactsForSource = (input: { · 7 unmodified lines | |||
| 128 | }); | 137 | }); |
| 129 | 138 | ||
| 130 | export const listSources = (input: { | 139 | export const listSources = (input: { |
| 131 | workspaceId: WorkspaceId; | 140 | scopeId: ScopeId; |
| 132 | accountId: AccountId; | 141 | actorScopeId: ScopeId; |
| 133 | }) => | 142 | }) => |
| 134 | Effect.flatMap(ExecutorStateStore, () => | 143 | Effect.flatMap(ExecutorStateStore, () => |
| 135 | Effect.gen(function* () { | 144 | Effect.gen(function* () { |
| 136 | const sourceStore = yield* RuntimeSourceStoreService; | 145 | const sourceStore = yield* RuntimeSourceStoreService; |
| 137 | 146 | ||
| 138 | return yield* sourceStore | 147 | return yield* sourceStore |
| 139 | .loadSourcesInWorkspace(input.workspaceId, { | 148 | .loadSourcesInScope(input.scopeId, { |
| 140 | actorAccountId: input.accountId, | 149 | actorScopeId: input.actorScopeId, |
| 141 | }) | 150 | }) |
| 142 | .pipe( | 151 | .pipe( |
| 143 | Effect.mapError((error) => | 152 | Effect.mapError((error) => |
| @@ -151,8 +160,8 @@ export const listSources = (input: { · 7 unmodified lines | |||
| 151 | ); | 160 | ); |
| 152 | 161 | ||
| 153 | export const createSource = (input: { | 162 | export const createSource = (input: { |
| 154 | workspaceId: WorkspaceId; | 163 | scopeId: ScopeId; |
| 155 | accountId: AccountId; | 164 | actorScopeId: ScopeId; |
| 156 | payload: CreateSourcePayload; | 165 | payload: CreateSourcePayload; |
| 157 | }) => | 166 | }) => |
| 158 | Effect.flatMap(ExecutorStateStore, (store) => | 167 | Effect.flatMap(ExecutorStateStore, (store) => |
| @@ -161,7 +170,7 @@ export const createSource = (input: { · 2 unmodified lines | |||
| 161 | const now = Date.now(); | 170 | const now = Date.now(); |
| 162 | 171 | ||
| 163 | const source = yield* createSourceFromPayload({ | 172 | const source = yield* createSourceFromPayload({ |
| 164 | workspaceId: input.workspaceId, | 173 | scopeId: input.scopeId, |
| 165 | sourceId: SourceIdSchema.make(`src_${crypto.randomUUID()}`), | 174 | sourceId: SourceIdSchema.make(`src_${crypto.randomUUID()}`), |
| 166 | payload: input.payload, | 175 | payload: input.payload, |
| 167 | now, | 176 | now, |
| @@ -177,7 +186,7 @@ export const createSource = (input: { · 9 unmodified lines | |||
| 177 | const persistedSource = yield* mapPersistenceError( | 186 | const persistedSource = yield* mapPersistenceError( |
| 178 | sourceOps.create.child("persist"), | 187 | sourceOps.create.child("persist"), |
| 179 | sourceStore.persistSource(source, { | 188 | sourceStore.persistSource(source, { |
| 180 | actorAccountId: input.accountId, | 189 | actorScopeId: input.actorScopeId, |
| 181 | }), | 190 | }), |
| 182 | ); | 191 | ); |
| 183 | 192 | ||
| @@ -185,7 +194,7 @@ export const createSource = (input: { · 1 unmodified line | |||
| 185 | store, | 194 | store, |
| 186 | sourceStore, | 195 | sourceStore, |
| 187 | source: persistedSource, | 196 | source: persistedSource, |
| 188 | actorAccountId: input.accountId, | 197 | actorScopeId: input.actorScopeId, |
| 189 | operation: sourceOps.create, | 198 | operation: sourceOps.create, |
| 190 | }); | 199 | }); |
| 191 | 200 | ||
| @@ -194,9 +203,9 @@ export const createSource = (input: { · 2 unmodified lines | |||
| 194 | ); | 203 | ); |
| 195 | 204 | ||
| 196 | export const getSource = (input: { | 205 | export const getSource = (input: { |
| 197 | workspaceId: WorkspaceId; | 206 | scopeId: ScopeId; |
| 198 | sourceId: SourceId; | 207 | sourceId: SourceId; |
| 199 | accountId: AccountId; | 208 | actorScopeId: ScopeId; |
| 200 | }) => | 209 | }) => |
| 201 | Effect.flatMap(ExecutorStateStore, () => | 210 | Effect.flatMap(ExecutorStateStore, () => |
| 202 | Effect.gen(function* () { | 211 | Effect.gen(function* () { |
| @@ -204,9 +213,9 @@ export const getSource = (input: { · 1 unmodified line | |||
| 204 | 213 | ||
| 205 | return yield* sourceStore | 214 | return yield* sourceStore |
| 206 | .loadSourceById({ | 215 | .loadSourceById({ |
| 207 | workspaceId: input.workspaceId, | 216 | scopeId: input.scopeId, |
| 208 | sourceId: input.sourceId, | 217 | sourceId: input.sourceId, |
| 209 | actorAccountId: input.accountId, | 218 | actorScopeId: input.actorScopeId, |
| 210 | }) | 219 | }) |
| 211 | .pipe( | 220 | .pipe( |
| 212 | Effect.mapError((cause) => | 221 | Effect.mapError((cause) => |
| @@ -214,7 +223,7 @@ export const getSource = (input: { · 1 unmodified line | |||
| 214 | cause.message.startsWith("Source not found:") | 223 | cause.message.startsWith("Source not found:") |
| 215 | ? sourceOps.get.notFound( | 224 | ? sourceOps.get.notFound( |
| 216 | "Source not found", | 225 | "Source not found", |
| 217 | `workspaceId=${input.workspaceId} sourceId=${input.sourceId}`, | 226 | `scopeId=${input.scopeId} sourceId=${input.sourceId}`, |
| 218 | ) | 227 | ) |
| 219 | : sourceOps.get.unknownStorage( | 228 | : sourceOps.get.unknownStorage( |
| 220 | cause, | 229 | cause, |
| @@ -226,9 +235,9 @@ export const getSource = (input: { · 5 unmodified lines | |||
| 226 | ); | 235 | ); |
| 227 | 236 | ||
| 228 | export const updateSource = (input: { | 237 | export const updateSource = (input: { |
| 229 | workspaceId: WorkspaceId; | 238 | scopeId: ScopeId; |
| 230 | sourceId: SourceId; | 239 | sourceId: SourceId; |
| 231 | accountId: AccountId; | 240 | actorScopeId: ScopeId; |
| 232 | payload: UpdateSourcePayload; | 241 | payload: UpdateSourcePayload; |
| 233 | }) => | 242 | }) => |
| 234 | Effect.flatMap(ExecutorStateStore, (store) => | 243 | Effect.flatMap(ExecutorStateStore, (store) => |
| @@ -236,9 +245,9 @@ export const updateSource = (input: { · 1 unmodified line | |||
| 236 | const sourceStore = yield* RuntimeSourceStoreService; | 245 | const sourceStore = yield* RuntimeSourceStoreService; |
| 237 | const existingSource = yield* sourceStore | 246 | const existingSource = yield* sourceStore |
| 238 | .loadSourceById({ | 247 | .loadSourceById({ |
| 239 | workspaceId: input.workspaceId, | 248 | scopeId: input.scopeId, |
| 240 | sourceId: input.sourceId, | 249 | sourceId: input.sourceId, |
| 241 | actorAccountId: input.accountId, | 250 | actorScopeId: input.actorScopeId, |
| 242 | }) | 251 | }) |
| 243 | .pipe( | 252 | .pipe( |
| 244 | Effect.mapError((cause) => | 253 | Effect.mapError((cause) => |
| @@ -246,7 +255,7 @@ export const updateSource = (input: { · 1 unmodified line | |||
| 246 | cause.message.startsWith("Source not found:") | 255 | cause.message.startsWith("Source not found:") |
| 247 | ? sourceOps.update.notFound( | 256 | ? sourceOps.update.notFound( |
| 248 | "Source not found", | 257 | "Source not found", |
| 249 | `workspaceId=${input.workspaceId} sourceId=${input.sourceId}`, | 258 | `scopeId=${input.scopeId} sourceId=${input.sourceId}`, |
| 250 | ) | 259 | ) |
| 251 | : sourceOps.update.unknownStorage( | 260 | : sourceOps.update.unknownStorage( |
| 252 | cause, | 261 | cause, |
| @@ -271,7 +280,7 @@ export const updateSource = (input: { · 18 unmodified lines | |||
| 271 | const persistedSource = yield* mapPersistenceError( | 280 | const persistedSource = yield* mapPersistenceError( |
| 272 | sourceOps.update.child("persist"), | 281 | sourceOps.update.child("persist"), |
| 273 | sourceStore.persistSource(updatedSource, { | 282 | sourceStore.persistSource(updatedSource, { |
| 274 | actorAccountId: input.accountId, | 283 | actorScopeId: input.actorScopeId, |
| 275 | }), | 284 | }), |
| 276 | ); | 285 | ); |
| 277 | 286 | ||
| @@ -279,7 +288,7 @@ export const updateSource = (input: { · 1 unmodified line | |||
| 279 | store, | 288 | store, |
| 280 | sourceStore, | 289 | sourceStore, |
| 281 | source: persistedSource, | 290 | source: persistedSource, |
| 282 | actorAccountId: input.accountId, | 291 | actorScopeId: input.actorScopeId, |
| 283 | operation: sourceOps.update, | 292 | operation: sourceOps.update, |
| 284 | }); | 293 | }); |
| 285 | 294 | ||
| @@ -288,7 +297,7 @@ export const updateSource = (input: { · 2 unmodified lines | |||
| 288 | ); | 297 | ); |
| 289 | 298 | ||
| 290 | export const removeSource = (input: { | 299 | export const removeSource = (input: { |
| 291 | workspaceId: WorkspaceId; | 300 | scopeId: ScopeId; |
| 292 | sourceId: SourceId; | 301 | sourceId: SourceId; |
| 293 | }) => | 302 | }) => |
| 294 | Effect.flatMap(ExecutorStateStore, () => | 303 | Effect.flatMap(ExecutorStateStore, () => |
| @@ -297,7 +306,7 @@ export const removeSource = (input: { · 2 unmodified lines | |||
| 297 | const removed = yield* mapPersistenceError( | 306 | const removed = yield* mapPersistenceError( |
| 298 | sourceOps.remove.child("remove"), | 307 | sourceOps.remove.child("remove"), |
| 299 | sourceStore.removeSourceById({ | 308 | sourceStore.removeSourceById({ |
| 300 | workspaceId: input.workspaceId, | 309 | scopeId: input.scopeId, |
| 301 | sourceId: input.sourceId, | 310 | sourceId: input.sourceId, |
| 302 | }), | 311 | }), |
| 303 | ); | 312 | ); |
| @@ -1,15 +0,0 @@ | |||
| 1 | import type { | ||
| 2 | AccountId, | ||
| 3 | WorkspaceId, | ||
| 4 | } from "./schema"; | ||
| 5 | |||
| 6 | export type ExecutorWorkspaceDescriptor = { | ||
| 7 | workspaceName: string; | ||
| 8 | workspaceRoot?: string | null; | ||
| 9 | metadata?: Readonly<Record<string, unknown>>; | ||
| 10 | }; | ||
| 11 | |||
| 12 | export type ExecutorWorkspaceContext = ExecutorWorkspaceDescriptor & { | ||
| 13 | workspaceId: WorkspaceId; | ||
| 14 | accountId: AccountId; | ||
| 15 | }; | ||
| @@ -134,7 +134,7 @@ export const SourceBindingSchema = Schema.Struct({ · 133 unmodified lines | |||
| 134 | 134 | ||
| 135 | export const SourceSchema = Schema.Struct({ | 135 | export const SourceSchema = Schema.Struct({ |
| 136 | id: Schema.String, | 136 | id: Schema.String, |
| 137 | workspaceId: Schema.String, | 137 | scopeId: Schema.String, |
| 138 | name: Schema.String, | 138 | name: Schema.String, |
| 139 | kind: SourceKindSchema, | 139 | kind: SourceKindSchema, |
| 140 | endpoint: Schema.String, | 140 | endpoint: Schema.String, |
| @@ -157,19 +157,19 @@ export const StoredSourceRecordSchema = Schema.Struct({ · 16 unmodified lines | |||
| 157 | bindingConfigJson: Schema.NullOr(Schema.String), | 157 | bindingConfigJson: Schema.NullOr(Schema.String), |
| 158 | }); | 158 | }); |
| 159 | 159 | ||
| 160 | export const WorkspaceSourceOauthClientRedirectModeSchema = Schema.Literal( | 160 | export const ScopedSourceOauthClientRedirectModeSchema = Schema.Literal( |
| 161 | "app_callback", | 161 | "app_callback", |
| 162 | "loopback", | 162 | "loopback", |
| 163 | ); | 163 | ); |
| 164 | 164 | ||
| 165 | export const WorkspaceOauthClientIdSchema = Schema.String; | 165 | export const ScopeOauthClientIdSchema = Schema.String; |
| 166 | 166 | ||
| 167 | export const SourceOauthClientInputSchema = Schema.Struct({ | 167 | export const SourceOauthClientInputSchema = Schema.Struct({ |
| 168 | clientId: Schema.Trim.pipe(Schema.nonEmptyString()), | 168 | clientId: Schema.Trim.pipe(Schema.nonEmptyString()), |
| 169 | clientSecret: Schema.optional( | 169 | clientSecret: Schema.optional( |
| 170 | Schema.NullOr(Schema.Trim.pipe(Schema.nonEmptyString())), | 170 | Schema.NullOr(Schema.Trim.pipe(Schema.nonEmptyString())), |
| 171 | ), | 171 | ), |
| 172 | redirectMode: Schema.optional(WorkspaceSourceOauthClientRedirectModeSchema), | 172 | redirectMode: Schema.optional(ScopedSourceOauthClientRedirectModeSchema), |
| 173 | }); | 173 | }); |
| 174 | 174 | ||
| 175 | export type SecretRef = typeof SecretRefSchema.Type; | 175 | export type SecretRef = typeof SecretRefSchema.Type; |
| @@ -185,6 +185,6 @@ export type SourceAuth = typeof SourceAuthSchema.Type; · 9 unmodified lines | |||
| 185 | export type SourceBinding = typeof SourceBindingSchema.Type; | 185 | export type SourceBinding = typeof SourceBindingSchema.Type; |
| 186 | export type Source = typeof SourceSchema.Type; | 186 | export type Source = typeof SourceSchema.Type; |
| 187 | export type StoredSourceRecord = typeof StoredSourceRecordSchema.Type; | 187 | export type StoredSourceRecord = typeof StoredSourceRecordSchema.Type; |
| 188 | export type WorkspaceSourceOauthClientRedirectMode = | 188 | export type ScopedSourceOauthClientRedirectMode = |
| 189 | typeof WorkspaceSourceOauthClientRedirectModeSchema.Type; | 189 | typeof ScopedSourceOauthClientRedirectModeSchema.Type; |
| 190 | export type SourceOauthClientInput = typeof SourceOauthClientInputSchema.Type; | 190 | export type SourceOauthClientInput = typeof SourceOauthClientInputSchema.Type; |
| @@ -81,7 +81,7 @@ const withJsonServer = async <T>(handler: (input: { · 80 unmodified lines | |||
| 81 | 81 | ||
| 82 | const makeGoogleDiscoverySource = (discoveryUrl: string): Source => ({ | 82 | const makeGoogleDiscoverySource = (discoveryUrl: string): Source => ({ |
| 83 | id: "src_google_gmail", | 83 | id: "src_google_gmail", |
| 84 | workspaceId: "ws_test", | 84 | scopeId: "ws_test", |
| 85 | name: "Gmail", | 85 | name: "Gmail", |
| 86 | kind: "google_discovery", | 86 | kind: "google_discovery", |
| 87 | endpoint: discoveryUrl, | 87 | endpoint: discoveryUrl, |
| @@ -38,7 +38,7 @@ import { · 37 unmodified lines | |||
| 38 | OptionalNullableStringSchema, | 38 | OptionalNullableStringSchema, |
| 39 | SourceCredentialRequiredError, | 39 | SourceCredentialRequiredError, |
| 40 | StringMapSchema, | 40 | StringMapSchema, |
| 41 | WorkspaceOauthClientIdSchema, | 41 | ScopeOauthClientIdSchema, |
| 42 | createCatalogImportMetadata, | 42 | createCatalogImportMetadata, |
| 43 | EXECUTABLE_BINDING_VERSION, | 43 | EXECUTABLE_BINDING_VERSION, |
| 44 | sourceCoreEffectError, | 44 | sourceCoreEffectError, |
| @@ -60,8 +60,8 @@ const GoogleDiscoveryConnectPayloadSchema = Schema.extend( · 15 unmodified lines | |||
| 60 | scopes: Schema.optional( | 60 | scopes: Schema.optional( |
| 61 | Schema.Array(Schema.Trim.pipe(Schema.nonEmptyString())), | 61 | Schema.Array(Schema.Trim.pipe(Schema.nonEmptyString())), |
| 62 | ), | 62 | ), |
| 63 | workspaceOauthClientId: Schema.optional( | 63 | scopeOauthClientId: Schema.optional( |
| 64 | Schema.NullOr(WorkspaceOauthClientIdSchema), | 64 | Schema.NullOr(ScopeOauthClientIdSchema), |
| 65 | ), | 65 | ), |
| 66 | oauthClient: ConnectOauthClientSchema, | 66 | oauthClient: ConnectOauthClientSchema, |
| 67 | name: OptionalNullableStringSchema, | 67 | name: OptionalNullableStringSchema, |
| @@ -14,6 +14,8 @@ Current rules: · 13 unmodified lines | |||
| 14 | - `executor-monorepo/no-cross-workspace-relative-imports` | 14 | - `executor-monorepo/no-cross-workspace-relative-imports` |
| 15 | - `executor-monorepo/no-direct-effect-tag-read` | 15 | - `executor-monorepo/no-direct-effect-tag-read` |
| 16 | - `executor-monorepo/no-effect-run-in-effect-vitest-tests` | 16 | - `executor-monorepo/no-effect-run-in-effect-vitest-tests` |
| 17 | - `executor-monorepo/no-manual-httpapi-openapi-bridge` | ||
| 18 | - `executor-monorepo/no-manual-openapi-documents` | ||
| 17 | - `executor-monorepo/no-node-fs-with-effect-imports` | 19 | - `executor-monorepo/no-node-fs-with-effect-imports` |
| 18 | - `executor-monorepo/no-raw-effect-fail-errors` | 20 | - `executor-monorepo/no-raw-effect-fail-errors` |
| 19 | - `executor-monorepo/no-yield-effect-fail` | 21 | - `executor-monorepo/no-yield-effect-fail` |
| @@ -4,6 +4,8 @@ import noCrossWorkspaceRelativeImports from "./rules/no-cross-workspace-relative · 3 unmodified lines | |||
| 4 | import noAsyncEffectVitestTests from "./rules/no-async-effect-vitest-tests.mjs"; | 4 | import noAsyncEffectVitestTests from "./rules/no-async-effect-vitest-tests.mjs"; |
| 5 | import noDirectEffectTagRead from "./rules/no-direct-effect-tag-read.mjs"; | 5 | import noDirectEffectTagRead from "./rules/no-direct-effect-tag-read.mjs"; |
| 6 | import noEffectRunInEffectVitestTests from "./rules/no-effect-run-in-effect-vitest-tests.mjs"; | 6 | import noEffectRunInEffectVitestTests from "./rules/no-effect-run-in-effect-vitest-tests.mjs"; |
| 7 | import noManualHttpApiOpenApiBridge from "./rules/no-manual-httpapi-openapi-bridge.mjs"; | ||
| 8 | import noManualOpenApiDocuments from "./rules/no-manual-openapi-documents.mjs"; | ||
| 7 | import noNodeFsWithEffectImports from "./rules/no-node-fs-with-effect-imports.mjs"; | 9 | import noNodeFsWithEffectImports from "./rules/no-node-fs-with-effect-imports.mjs"; |
| 8 | import noRawEffectFailErrors from "./rules/no-raw-effect-fail-errors.mjs"; | 10 | import noRawEffectFailErrors from "./rules/no-raw-effect-fail-errors.mjs"; |
| 9 | import noYieldEffectFail from "./rules/no-yield-effect-fail.mjs"; | 11 | import noYieldEffectFail from "./rules/no-yield-effect-fail.mjs"; |
| @@ -18,6 +20,8 @@ export default definePlugin({ · 8 unmodified lines | |||
| 18 | "no-cross-workspace-relative-imports": noCrossWorkspaceRelativeImports, | 20 | "no-cross-workspace-relative-imports": noCrossWorkspaceRelativeImports, |
| 19 | "no-direct-effect-tag-read": noDirectEffectTagRead, | 21 | "no-direct-effect-tag-read": noDirectEffectTagRead, |
| 20 | "no-effect-run-in-effect-vitest-tests": noEffectRunInEffectVitestTests, | 22 | "no-effect-run-in-effect-vitest-tests": noEffectRunInEffectVitestTests, |
| 23 | "no-manual-httpapi-openapi-bridge": noManualHttpApiOpenApiBridge, | ||
| 24 | "no-manual-openapi-documents": noManualOpenApiDocuments, | ||
| 21 | "no-node-fs-with-effect-imports": noNodeFsWithEffectImports, | 25 | "no-node-fs-with-effect-imports": noNodeFsWithEffectImports, |
| 22 | "no-raw-effect-fail-errors": noRawEffectFailErrors, | 26 | "no-raw-effect-fail-errors": noRawEffectFailErrors, |
| 23 | "no-yield-effect-fail": noYieldEffectFail, | 27 | "no-yield-effect-fail": noYieldEffectFail, |
| @@ -0,0 +1,65 @@ | |||
| 1 | import { readFileSync } from "node:fs"; | ||
| 2 | import { defineRule } from "@oxlint/plugins"; | ||
| 3 | |||
| 4 | const isTestLikeFile = (filename) => | ||
| 5 | filename.includes(".test.") | ||
| 6 | || filename.includes(".spec.") | ||
| 7 | || filename.endsWith(".test.ts") | ||
| 8 | || filename.endsWith(".test.tsx") | ||
| 9 | || filename.endsWith(".spec.ts") | ||
| 10 | || filename.endsWith(".spec.tsx"); | ||
| 11 | |||
| 12 | const readsLikeOpenApiHttpApiTest = (filename) => { | ||
| 13 | try { | ||
| 14 | const sourceText = readFileSync(filename, "utf8"); | ||
| 15 | return sourceText.includes("HttpApiBuilder.middlewareOpenApi(") | ||
| 16 | || sourceText.includes("OpenApi.fromApi("); | ||
| 17 | } catch { | ||
| 18 | return false; | ||
| 19 | } | ||
| 20 | }; | ||
| 21 | |||
| 22 | const isHttpApiBuilderCall = (node, methodName) => | ||
| 23 | node?.type === "CallExpression" | ||
| 24 | && node.callee?.type === "MemberExpression" | ||
| 25 | && node.callee.computed === false | ||
| 26 | && node.callee.object?.type === "Identifier" | ||
| 27 | && node.callee.object.name === "HttpApiBuilder" | ||
| 28 | && node.callee.property?.type === "Identifier" | ||
| 29 | && node.callee.property.name === methodName; | ||
| 30 | |||
| 31 | export default defineRule({ | ||
| 32 | meta: { | ||
| 33 | type: "problem", | ||
| 34 | docs: { | ||
| 35 | description: | ||
| 36 | "Disallow manual Node/Web bridges around Effect HttpApi when serving OpenAPI test servers.", | ||
| 37 | recommended: true, | ||
| 38 | }, | ||
| 39 | messages: { | ||
| 40 | noManualHttpApiOpenApiBridge: | ||
| 41 | "Do not serve OpenAPI test servers by manually bridging `HttpApiBuilder.toWebHandler(...)` to Node HTTP. Use `@executor/effect-test-utils` (`startOpenApiTestServer` / `makeOpenApiTestServer`) instead.", | ||
| 42 | }, | ||
| 43 | }, | ||
| 44 | create(context) { | ||
| 45 | if ( | ||
| 46 | !isTestLikeFile(context.filename) | ||
| 47 | || !readsLikeOpenApiHttpApiTest(context.filename) | ||
| 48 | ) { | ||
| 49 | return {}; | ||
| 50 | } | ||
| 51 | |||
| 52 | return { | ||
| 53 | CallExpression(node) { | ||
| 54 | if (!isHttpApiBuilderCall(node, "toWebHandler")) { | ||
| 55 | return; | ||
| 56 | } | ||
| 57 | |||
| 58 | context.report({ | ||
| 59 | node, | ||
| 60 | messageId: "noManualHttpApiOpenApiBridge", | ||
| 61 | }); | ||
| 62 | }, | ||
| 63 | }; | ||
| 64 | }, | ||
| 65 | }); | ||
| @@ -0,0 +1,108 @@ | |||
| 1 | import path from "node:path"; | ||
| 2 | import { defineRule } from "@oxlint/plugins"; | ||
| 3 | |||
| 4 | const MANUAL_OPENAPI_RULE_ALLOWED_PATH_SEGMENTS = [ | ||
| 5 | `${path.sep}packages${path.sep}sources${path.sep}openapi${path.sep}`, | ||
| 6 | `${path.sep}packages${path.sep}platform${path.sep}sdk${path.sep}src${path.sep}runtime${path.sep}sources${path.sep}source-adapter-fixture-matrix.test.ts`, | ||
| 7 | `${path.sep}packages${path.sep}platform${path.sep}sdk${path.sep}src${path.sep}runtime${path.sep}sources${path.sep}source-discovery.test.ts`, | ||
| 8 | ]; | ||
| 9 | |||
| 10 | const OPENAPI_MARKER_KEYS = new Set(["openapi", "swagger"]); | ||
| 11 | const OPENAPI_SHAPE_KEYS = new Set([ | ||
| 12 | "components", | ||
| 13 | "info", | ||
| 14 | "paths", | ||
| 15 | "responses", | ||
| 16 | "security", | ||
| 17 | "servers", | ||
| 18 | "tags", | ||
| 19 | ]); | ||
| 20 | |||
| 21 | const isTestLikeFile = (filename) => | ||
| 22 | filename.includes(".test.") | ||
| 23 | || filename.includes(".spec.") | ||
| 24 | || filename.endsWith(".test.ts") | ||
| 25 | || filename.endsWith(".test.tsx") | ||
| 26 | || filename.endsWith(".spec.ts") | ||
| 27 | || filename.endsWith(".spec.tsx"); | ||
| 28 | |||
| 29 | const isAllowedFile = (filename) => | ||
| 30 | MANUAL_OPENAPI_RULE_ALLOWED_PATH_SEGMENTS.some((segment) => | ||
| 31 | filename.includes(segment) | ||
| 32 | ); | ||
| 33 | |||
| 34 | const readPropertyKey = (node) => { | ||
| 35 | if (!node || node.type !== "Property" || node.computed) { | ||
| 36 | return null; | ||
| 37 | } | ||
| 38 | |||
| 39 | const key = node.key; | ||
| 40 | if (!key) { | ||
| 41 | return null; | ||
| 42 | } | ||
| 43 | |||
| 44 | if (key.type === "Identifier") { | ||
| 45 | return key.name; | ||
| 46 | } | ||
| 47 | |||
| 48 | if (key.type === "Literal" && typeof key.value === "string") { | ||
| 49 | return key.value; | ||
| 50 | } | ||
| 51 | |||
| 52 | return null; | ||
| 53 | }; | ||
| 54 | |||
| 55 | const objectExpressionKeys = (node) => { | ||
| 56 | if (!node || node.type !== "ObjectExpression") { | ||
| 57 | return []; | ||
| 58 | } | ||
| 59 | |||
| 60 | return node.properties | ||
| 61 | .map(readPropertyKey) | ||
| 62 | .filter((key) => typeof key === "string"); | ||
| 63 | }; | ||
| 64 | |||
| 65 | const looksLikeOpenApiDocument = (node) => { | ||
| 66 | if (!node || node.type !== "ObjectExpression") { | ||
| 67 | return false; | ||
| 68 | } | ||
| 69 | |||
| 70 | const keys = new Set(objectExpressionKeys(node)); | ||
| 71 | const hasOpenApiMarker = [...OPENAPI_MARKER_KEYS].some((key) => keys.has(key)); | ||
| 72 | const hasOpenApiShape = [...OPENAPI_SHAPE_KEYS].some((key) => keys.has(key)); | ||
| 73 | |||
| 74 | return hasOpenApiMarker && hasOpenApiShape; | ||
| 75 | }; | ||
| 76 | |||
| 77 | export default defineRule({ | ||
| 78 | meta: { | ||
| 79 | type: "problem", | ||
| 80 | docs: { | ||
| 81 | description: | ||
| 82 | "Disallow hand-authored inline OpenAPI documents in normal test files.", | ||
| 83 | recommended: true, | ||
| 84 | }, | ||
| 85 | messages: { | ||
| 86 | noManualOpenApiDocuments: | ||
| 87 | "Do not hand-author inline OpenAPI documents here. Use Effect's HttpApi/OpenApi builders, such as `OpenApi.fromApi(...)`, instead. Raw OpenAPI fixtures should live only in dedicated OpenAPI parser/import tests.", | ||
| 88 | }, | ||
| 89 | }, | ||
| 90 | create(context) { | ||
| 91 | if (!isTestLikeFile(context.filename) || isAllowedFile(context.filename)) { | ||
| 92 | return {}; | ||
| 93 | } | ||
| 94 | |||
| 95 | return { | ||
| 96 | ObjectExpression(node) { | ||
| 97 | if (!looksLikeOpenApiDocument(node)) { | ||
| 98 | return; | ||
| 99 | } | ||
| 100 | |||
| 101 | context.report({ | ||
| 102 | node, | ||
| 103 | messageId: "noManualOpenApiDocuments", | ||
| 104 | }); | ||
| 105 | }, | ||
| 106 | }; | ||
| 107 | }, | ||
| 108 | }); | ||