Unified · Split
| @@ -1,22 +1,117 @@ | ||
| 1 | 1 | { |
| 2 | 2 | "sources": { |
| 3 | 3 | "github": { |
| 4 | − "kind": "openapi", | |
| 5 | 4 | "name": "GitHub", |
| 6 | 5 | "connection": { |
| 7 | − "endpoint": "https://api.github.com/" | |
| 6 | + "endpoint": "https://api.github.com" | |
| 8 | 7 | }, |
| 8 | + "kind": "openapi", | |
| 9 | 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 | 11 | "defaultHeaders": null |
| 12 | 12 | } |
| 13 | − } | |
| 14 | − }, | |
| 15 | − "policies": { | |
| 16 | − "demo.*": { | |
| 17 | − "match": "demo.*", | |
| 18 | − "action": "allow", | |
| 19 | − "approval": "auto" | |
| 13 | + }, | |
| 14 | + "googleapis": { | |
| 15 | + "name": "Drive", | |
| 16 | + "namespace": "google.drive", | |
| 17 | + "connection": { | |
| 18 | + "endpoint": "http://127.0.0.1:60144/drive/$discovery/rest?version=v3" | |
| 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 | 43 | "executor-monorepo/no-cross-workspace-relative-imports": "error", |
| 44 | 44 | "executor-monorepo/no-direct-effect-tag-read": "error", |
| 45 | 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 | 48 | "executor-monorepo/no-node-fs-with-effect-imports": "error", |
| 47 | 49 | "executor-monorepo/no-raw-effect-fail-errors": "error", |
| 48 | 50 | "executor-monorepo/no-yield-effect-fail": "error", |
| @@ -50,6 +52,17 @@ · 1 unmodified line | ||
| 50 | 52 | }, |
| 51 | 53 | |
| 52 | 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 | 67 | // JSON Schema conditionals legitimately use a `then` key. |
| 55 | 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 | 45 | "effect": "catalog:" |
| 46 | 46 | }, |
| 47 | 47 | "devDependencies": { |
| 48 | + "@executor/effect-test-utils": "workspace:*", | |
| 48 | 49 | "@executor/mcp-elicitation-demo": "workspace:*", |
| 49 | 50 | "@executor/runtime-ses": "workspace:*", |
| 50 | 51 | "@effect/vitest": "catalog:", |
| @@ -1,5 +1,5 @@ | ||
| 1 | 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 | 3 | import * as Effect from "effect/Effect"; |
| 4 | 4 | |
| 5 | 5 | const readBindingString = (binding: Record<string, unknown>, key: string): string | null => |
| @@ -41,7 +41,7 @@ export const seedDemoMcpSourceInWorkspace = ( · 35 unmodified lines | ||
| 41 | 41 | input: SeedDemoMcpSourceInput, |
| 42 | 42 | ): Effect.Effect<SeedDemoMcpSourceResult, unknown, never> => |
| 43 | 43 | Effect.gen(function* () { |
| 44 | − const workspaceId = WorkspaceIdSchema.make(input.workspaceId); | |
| 44 | + const workspaceId = ScopeIdSchema.make(input.workspaceId); | |
| 45 | 45 | |
| 46 | 46 | const existing = yield* input.client.sources.list({ |
| 47 | 47 | path: { |
| @@ -138,7 +138,7 @@ export const seedGithubOpenApiSourceInWorkspace = ( · 90 unmodified lines | ||
| 138 | 138 | input: SeedGithubOpenApiSourceInput, |
| 139 | 139 | ): Effect.Effect<SeedDemoMcpSourceResult, unknown, never> => |
| 140 | 140 | Effect.gen(function* () { |
| 141 | − const workspaceId = WorkspaceIdSchema.make(input.workspaceId); | |
| 141 | + const workspaceId = ScopeIdSchema.make(input.workspaceId); | |
| 142 | 142 | |
| 143 | 143 | const existing = yield* input.client.sources.list({ |
| 144 | 144 | path: { |
| @@ -289,8 +289,8 @@ const loadRunWorkflowText = (): Effect.Effect<string, Error, never> => · 288 unmodified lines | ||
| 289 | 289 | const environment = yield* Effect.gen(function* () { |
| 290 | 290 | const resolveExecutionEnvironment = yield* RuntimeExecutionResolverService; |
| 291 | 291 | return yield* resolveExecutionEnvironment({ |
| 292 | − workspaceId: executor.workspaceId, | |
| 293 | − accountId: executor.accountId, | |
| 292 | + scopeId: executor.scopeId, | |
| 293 | + actorScopeId: executor.actorScopeId, | |
| 294 | 294 | executionId: ExecutionIdSchema.make("exec_help"), |
| 295 | 295 | }); |
| 296 | 296 | }).pipe( |
| @@ -403,7 +403,7 @@ const getLocalAuthedClient = (baseUrl: string = DEFAULT_SERVER_BASE_URL) => · 106 unmodified lines | ||
| 403 | 403 | const installation = yield* bootstrapClient.local.installation({}); |
| 404 | 404 | const client = yield* createExecutorApiClient({ |
| 405 | 405 | baseUrl, |
| 406 | − accountId: installation.accountId, | |
| 406 | + accountId: installation.actorScopeId, | |
| 407 | 407 | }); |
| 408 | 408 | |
| 409 | 409 | return { |
| @@ -574,6 +574,10 @@ const getServerStatus = ( · 164 unmodified lines | ||
| 574 | 574 | const installation = reachable |
| 575 | 575 | ? yield* getBootstrapClient(baseUrl).pipe( |
| 576 | 576 | Effect.flatMap((client) => client.local.installation({})), |
| 577 | + Effect.map((installation) => ({ | |
| 578 | + accountId: installation.actorScopeId, | |
| 579 | + workspaceId: installation.scopeId, | |
| 580 | + })), | |
| 577 | 581 | Effect.catchAll(() => Effect.succeed(null)), |
| 578 | 582 | ) |
| 579 | 583 | : null; |
| @@ -923,7 +927,7 @@ const promptInteraction = (input: { · 343 unmodified lines | ||
| 923 | 927 | |
| 924 | 928 | const waitForExecutionProgress = (input: { |
| 925 | 929 | client: ExecutorApiClient; |
| 926 | − workspaceId: ExecutionEnvelope["execution"]["workspaceId"]; | |
| 930 | + workspaceId: ExecutionEnvelope["execution"]["scopeId"]; | |
| 927 | 931 | executionId: ExecutionEnvelope["execution"]["id"]; |
| 928 | 932 | pendingInteractionId: ExecutionInteraction["id"]; |
| 929 | 933 | }) => |
| @@ -987,7 +991,7 @@ const seedDemoMcpSource = (input: { · 57 unmodified lines | ||
| 987 | 991 | const { installation, client } = yield* getLocalAuthedClient(input.baseUrl); |
| 988 | 992 | const result = yield* seedDemoMcpSourceInWorkspace({ |
| 989 | 993 | client, |
| 990 | − workspaceId: installation.workspaceId, | |
| 994 | + workspaceId: installation.scopeId, | |
| 991 | 995 | endpoint: input.endpoint, |
| 992 | 996 | name: input.name, |
| 993 | 997 | namespace: input.namespace, |
| @@ -1011,7 +1015,7 @@ const seedGithubOpenApiSource = (input: { · 17 unmodified lines | ||
| 1011 | 1015 | const { installation, client } = yield* getLocalAuthedClient(input.baseUrl); |
| 1012 | 1016 | const result = yield* seedGithubOpenApiSourceInWorkspace({ |
| 1013 | 1017 | client, |
| 1014 | − workspaceId: installation.workspaceId, | |
| 1018 | + workspaceId: installation.scopeId, | |
| 1015 | 1019 | endpoint: input.endpoint, |
| 1016 | 1020 | specUrl: input.specUrl, |
| 1017 | 1021 | name: input.name, |
| @@ -1026,7 +1030,7 @@ const seedGithubOpenApiSource = (input: { · 8 unmodified lines | ||
| 1026 | 1030 | |
| 1027 | 1031 | const driveExecution = (input: { |
| 1028 | 1032 | client: ExecutorApiClient; |
| 1029 | − workspaceId: ExecutionEnvelope["execution"]["workspaceId"]; | |
| 1033 | + workspaceId: ExecutionEnvelope["execution"]["scopeId"]; | |
| 1030 | 1034 | envelope: ExecutionEnvelope; |
| 1031 | 1035 | baseUrl: string; |
| 1032 | 1036 | shouldOpenUrls: boolean; |
| @@ -1297,7 +1301,7 @@ const callCommand = Command.make( · 264 unmodified lines | ||
| 1297 | 1301 | const { installation, client } = yield* getLocalAuthedClient(baseUrl); |
| 1298 | 1302 | const created = yield* client.executions.create({ |
| 1299 | 1303 | path: { |
| 1300 | − workspaceId: installation.workspaceId, | |
| 1304 | + workspaceId: installation.scopeId, | |
| 1301 | 1305 | }, |
| 1302 | 1306 | payload: { |
| 1303 | 1307 | code: resolvedCode, |
| @@ -1307,7 +1311,7 @@ const callCommand = Command.make( · 3 unmodified lines | ||
| 1307 | 1311 | |
| 1308 | 1312 | const settled = yield* driveExecution({ |
| 1309 | 1313 | client, |
| 1310 | − workspaceId: installation.workspaceId, | |
| 1314 | + workspaceId: installation.scopeId, | |
| 1311 | 1315 | envelope: created, |
| 1312 | 1316 | baseUrl, |
| 1313 | 1317 | shouldOpenUrls: !noOpen, |
| @@ -1333,14 +1337,14 @@ const resumeCommand = Command.make( · 19 unmodified lines | ||
| 1333 | 1337 | ); |
| 1334 | 1338 | const execution = yield* client.executions.get({ |
| 1335 | 1339 | path: { |
| 1336 | − workspaceId: installation.workspaceId, | |
| 1340 | + workspaceId: installation.scopeId, | |
| 1337 | 1341 | executionId: decodedExecutionId, |
| 1338 | 1342 | }, |
| 1339 | 1343 | }); |
| 1340 | 1344 | |
| 1341 | 1345 | const settled = yield* driveExecution({ |
| 1342 | 1346 | client, |
| 1343 | − workspaceId: installation.workspaceId, | |
| 1347 | + workspaceId: installation.scopeId, | |
| 1344 | 1348 | envelope: execution, |
| 1345 | 1349 | baseUrl, |
| 1346 | 1350 | shouldOpenUrls: !noOpen, |
| @@ -65,8 +65,8 @@ describe("distribution flow", () => { · 64 unmodified lines | ||
| 65 | 65 | const installationResponse = yield* harness.fetchText("/v1/local/installation"); |
| 66 | 66 | expect(installationResponse.status).toBe(200); |
| 67 | 67 | const installation = JSON.parse(installationResponse.body) as { |
| 68 | − workspaceId: string; | |
| 69 | − accountId: string; | |
| 68 | + scopeId: string; | |
| 69 | + actorScopeId: string; | |
| 70 | 70 | }; |
| 71 | 71 | |
| 72 | 72 | const sesCall = yield* runCommand( |
| @@ -88,12 +88,12 @@ describe("distribution flow", () => { · 15 unmodified lines | ||
| 88 | 88 | const installationAfterRestart = JSON.parse( |
| 89 | 89 | installationAfterRestartResponse.body, |
| 90 | 90 | ) as { |
| 91 | − workspaceId: string; | |
| 92 | − accountId: string; | |
| 91 | + scopeId: string; | |
| 92 | + actorScopeId: string; | |
| 93 | 93 | }; |
| 94 | 94 | |
| 95 | − expect(installationAfterRestart.workspaceId).toBe(installation.workspaceId); | |
| 96 | − expect(installationAfterRestart.accountId).toBe(installation.accountId); | |
| 95 | + expect(installationAfterRestart.scopeId).toBe(installation.scopeId); | |
| 96 | + expect(installationAfterRestart.actorScopeId).toBe(installation.actorScopeId); | |
| 97 | 97 | |
| 98 | 98 | yield* runCommand(["down", "--base-url", harness.baseUrl]); |
| 99 | 99 | }); |
| @@ -39,7 +39,7 @@ const createApiClientHarness = () => · 38 unmodified lines | ||
| 39 | 39 | const installation = yield* bootstrapClient.local.installation({}); |
| 40 | 40 | const client = yield* createExecutorApiClient({ |
| 41 | 41 | baseUrl: server.baseUrl, |
| 42 | − accountId: installation.accountId, | |
| 42 | + accountId: installation.actorScopeId, | |
| 43 | 43 | }); |
| 44 | 44 | |
| 45 | 45 | return { |
| @@ -75,7 +75,7 @@ describe("local-executor-server real ingestion", () => { · 29 unmodified lines | ||
| 75 | 75 | |
| 76 | 76 | const connected = yield* client.sources.connect({ |
| 77 | 77 | path: { |
| 78 | − workspaceId: installation.workspaceId, | |
| 78 | + workspaceId: installation.scopeId, | |
| 79 | 79 | }, |
| 80 | 80 | payload: { |
| 81 | 81 | kind: "openapi", |
| @@ -96,7 +96,7 @@ describe("local-executor-server real ingestion", () => { · 14 unmodified lines | ||
| 96 | 96 | |
| 97 | 97 | const inspection = yield* client.sources.inspection({ |
| 98 | 98 | path: { |
| 99 | − workspaceId: installation.workspaceId, | |
| 99 | + workspaceId: installation.scopeId, | |
| 100 | 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 | 107 | const discoveredTools = yield* client.sources.inspectionDiscover({ |
| 108 | 108 | path: { |
| 109 | − workspaceId: installation.workspaceId, | |
| 109 | + workspaceId: installation.scopeId, | |
| 110 | 110 | sourceId: connected.source.id, |
| 111 | 111 | }, |
| 112 | 112 | payload: { |
| @@ -137,7 +137,7 @@ describe("local-executor-server real ingestion", () => { · 24 unmodified lines | ||
| 137 | 137 | |
| 138 | 138 | const connected = yield* client.sources.connect({ |
| 139 | 139 | path: { |
| 140 | − workspaceId: installation.workspaceId, | |
| 140 | + workspaceId: installation.scopeId, | |
| 141 | 141 | }, |
| 142 | 142 | payload: { |
| 143 | 143 | kind: "graphql", |
| @@ -159,7 +159,7 @@ describe("local-executor-server real ingestion", () => { · 15 unmodified lines | ||
| 159 | 159 | |
| 160 | 160 | const inspection = yield* client.sources.inspection({ |
| 161 | 161 | path: { |
| 162 | − workspaceId: installation.workspaceId, | |
| 162 | + workspaceId: installation.scopeId, | |
| 163 | 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 | 176 | const toolDetail = yield* client.sources.inspectionTool({ |
| 177 | 177 | path: { |
| 178 | − workspaceId: installation.workspaceId, | |
| 178 | + workspaceId: installation.scopeId, | |
| 179 | 179 | sourceId: connected.source.id, |
| 180 | 180 | toolPath: "linear.administrableTeams", |
| 181 | 181 | }, |
| @@ -191,7 +191,7 @@ describe("local-executor-server real ingestion", () => { · 9 unmodified lines | ||
| 191 | 191 | |
| 192 | 192 | const storedSource = yield* client.sources.get({ |
| 193 | 193 | path: { |
| 194 | − workspaceId: installation.workspaceId, | |
| 194 | + workspaceId: installation.scopeId, | |
| 195 | 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 | 219 | const connected = yield* client.sources.connect({ |
| 220 | 220 | path: { |
| 221 | − workspaceId: installation.workspaceId, | |
| 221 | + workspaceId: installation.scopeId, | |
| 222 | 222 | }, |
| 223 | 223 | payload: { |
| 224 | 224 | kind: "mcp", |
| @@ -235,7 +235,7 @@ describe("local-executor-server real ingestion", () => { · 10 unmodified lines | ||
| 235 | 235 | |
| 236 | 236 | const inspection = yield* client.sources.inspection({ |
| 237 | 237 | path: { |
| 238 | − workspaceId: installation.workspaceId, | |
| 238 | + workspaceId: installation.scopeId, | |
| 239 | 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 | 246 | const discoveredTools = yield* client.sources.inspectionDiscover({ |
| 247 | 247 | path: { |
| 248 | − workspaceId: installation.workspaceId, | |
| 248 | + workspaceId: installation.scopeId, | |
| 249 | 249 | sourceId: connected.source.id, |
| 250 | 250 | }, |
| 251 | 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 | 2 | import { randomUUID } from "node:crypto"; |
| 3 | 3 | |
| 4 | 4 | import { |
| @@ -6,17 +6,19 @@ import { · 1 unmodified line | ||
| 6 | 6 | HttpApiEndpoint, |
| 7 | 7 | HttpApiGroup, |
| 8 | 8 | HttpApiSchema, |
| 9 | − OpenApi, | |
| 9 | + HttpApiBuilder, | |
| 10 | 10 | FileSystem, |
| 11 | 11 | } from "@effect/platform"; |
| 12 | 12 | import { NodeFileSystem } from "@effect/platform-node"; |
| 13 | 13 | import { describe, expect, it } from "@effect/vitest"; |
| 14 | 14 | import { assertTrue } from "@effect/vitest/utils"; |
| 15 | 15 | import * as Effect from "effect/Effect"; |
| 16 | +import * as Layer from "effect/Layer"; | |
| 16 | 17 | import * as Schema from "effect/Schema"; |
| 17 | 18 | |
| 18 | 19 | import { startMcpElicitationDemoServer } from "@executor/mcp-elicitation-demo"; |
| 19 | 20 | import { makeToolInvokerFromTools, toTool } from "@executor/codemode-core"; |
| 21 | +import { startOpenApiTestServer } from "@executor/effect-test-utils"; | |
| 20 | 22 | import { |
| 21 | 23 | createExecutorApiClient, |
| 22 | 24 | executorOpenApiSpec, |
| @@ -122,7 +124,7 @@ const writeConfiguredLocalMcpSource = (input: { · 99 unmodified lines | ||
| 122 | 124 | |
| 123 | 125 | const source = { |
| 124 | 126 | id: sourceId, |
| 125 | − workspaceId: installation.workspaceId, | |
| 127 | + scopeId: installation.scopeId, | |
| 126 | 128 | name: input.name ?? "Demo", |
| 127 | 129 | kind: "mcp" as const, |
| 128 | 130 | endpoint: input.endpoint, |
| @@ -196,7 +198,7 @@ const createApiClientHarness = () => · 67 unmodified lines | ||
| 196 | 198 | const installation = yield* bootstrapClient.local.installation({}); |
| 197 | 199 | const client = yield* createExecutorApiClient({ |
| 198 | 200 | baseUrl: server.baseUrl, |
| 199 | − accountId: installation.accountId, | |
| 201 | + accountId: installation.actorScopeId, | |
| 200 | 202 | }); |
| 201 | 203 | |
| 202 | 204 | return { |
| @@ -288,161 +290,89 @@ const repoParam = HttpApiSchema.param("repo", Schema.String); · 85 unmodified lines | ||
| 288 | 290 | class ExecutorDemoReposApi extends HttpApiGroup.make("repos") |
| 289 | 291 | .add( |
| 290 | 292 | HttpApiEndpoint.get("getRepo")`/repos/${ownerParam}/${repoParam}` |
| 291 | − .addSuccess( | |
| 292 | − Schema.Struct({ | |
| 293 | − full_name: Schema.String, | |
| 294 | − private: Schema.Boolean, | |
| 295 | − }), | |
| 296 | − ), | |
| 293 | + .addSuccess(Schema.Unknown), | |
| 297 | 294 | ) |
| 298 | 295 | {} |
| 299 | 296 | |
| 300 | 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 | 317 | const startOpenApiDemoServer = async () => { |
| 305 | 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) => { | |
| 308 | − if (req.url === "/openapi.json") { | |
| 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] ?? "")}`, | |
| 331 | + return Effect.succeed({ | |
| 332 | + full_name: `${path.owner}/${path.repo}`, | |
| 325 | 333 | private: false, |
| 326 | − }), | |
| 327 | − ); | |
| 328 | − return; | |
| 329 | − } | |
| 330 | − | |
| 331 | − res.statusCode = 404; | |
| 332 | − res.end("not found"); | |
| 333 | − }; | |
| 334 | + }); | |
| 335 | + }), | |
| 336 | + ); | |
| 334 | 337 | |
| 335 | − const server = createServer(handler); | |
| 336 | − await new Promise<void>((resolve, reject) => { | |
| 337 | − server.once("error", reject); | |
| 338 | − server.listen(0, "127.0.0.1", () => resolve()); | |
| 338 | + const server = await startOpenApiTestServer({ | |
| 339 | + apiLayer: HttpApiBuilder.api(ExecutorDemoApi).pipe( | |
| 340 | + Layer.provide(executorDemoLive), | |
| 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 | 344 | return { |
| 346 | − baseUrl: `http://127.0.0.1:${address.port}`, | |
| 347 | − specUrl: `http://127.0.0.1:${address.port}/openapi.json`, | |
| 345 | + ...server, | |
| 348 | 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 | 350 | const startMutatingOpenApiDemoServer = async () => { |
| 357 | 351 | const createdBodies: Array<Record<string, unknown>> = []; |
| 358 | − const openApiDocument = JSON.stringify({ | |
| 359 | − openapi: "3.0.3", | |
| 360 | − info: { | |
| 361 | − title: "Executor DNS Demo API", | |
| 362 | − version: "1.0.0", | |
| 363 | − }, | |
| 364 | − paths: { | |
| 365 | − "/records": { | |
| 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({ | |
| 352 | + const executorDnsLive = HttpApiBuilder.group( | |
| 353 | + ExecutorDnsApi, | |
| 354 | + "records", | |
| 355 | + (handlers) => | |
| 356 | + handlers.handle("createRecord", ({ payload }) => { | |
| 357 | + createdBodies.push(payload); | |
| 358 | + | |
| 359 | + return Effect.succeed({ | |
| 416 | 360 | ok: true, |
| 417 | 361 | id: `rec_${createdBodies.length}`, |
| 418 | − record: parsed, | |
| 419 | − })); | |
| 420 | − }); | |
| 421 | − return; | |
| 422 | − } | |
| 423 | − | |
| 424 | − res.statusCode = 404; | |
| 425 | − res.end("not found"); | |
| 426 | − }; | |
| 362 | + record: payload, | |
| 363 | + }); | |
| 364 | + }), | |
| 365 | + ); | |
| 427 | 366 | |
| 428 | − const server = createServer(handler); | |
| 429 | − await new Promise<void>((resolve, reject) => { | |
| 430 | − server.once("error", reject); | |
| 431 | − server.listen(0, "127.0.0.1", () => resolve()); | |
| 367 | + const server = await startOpenApiTestServer({ | |
| 368 | + apiLayer: HttpApiBuilder.api(ExecutorDnsApi).pipe( | |
| 369 | + Layer.provide(executorDnsLive), | |
| 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 | 373 | return { |
| 439 | − baseUrl: `http://127.0.0.1:${address.port}`, | |
| 440 | − specUrl: `http://127.0.0.1:${address.port}/openapi.json`, | |
| 374 | + ...server, | |
| 441 | 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 | 680 | const installation = yield* bootstrapClient.local.installation({}); |
| 751 | 681 | const client = yield* createExecutorApiClient({ |
| 752 | 682 | baseUrl: server.baseUrl, |
| 753 | − accountId: installation.accountId, | |
| 683 | + accountId: installation.actorScopeId, | |
| 754 | 684 | }); |
| 755 | 685 | |
| 756 | 686 | const execution = yield* client.executions.create({ |
| 757 | 687 | path: { |
| 758 | − workspaceId: installation.workspaceId, | |
| 688 | + workspaceId: installation.scopeId, | |
| 759 | 689 | }, |
| 760 | 690 | payload: { |
| 761 | 691 | code: "return await tools.math.add({ a: 20, b: 22 });", |
| @@ -951,12 +881,12 @@ describe("local-executor-server", () => { · 189 unmodified lines | ||
| 951 | 881 | const installation = yield* bootstrapClient.local.installation({}); |
| 952 | 882 | const client = yield* createExecutorApiClient({ |
| 953 | 883 | baseUrl: server.baseUrl, |
| 954 | − accountId: installation.accountId, | |
| 884 | + accountId: installation.actorScopeId, | |
| 955 | 885 | }); |
| 956 | 886 | |
| 957 | 887 | yield* client.sources.create({ |
| 958 | 888 | path: { |
| 959 | − workspaceId: installation.workspaceId, | |
| 889 | + workspaceId: installation.scopeId, | |
| 960 | 890 | }, |
| 961 | 891 | payload: { |
| 962 | 892 | name: "Demo", |
| @@ -978,7 +908,7 @@ describe("local-executor-server", () => { · 15 unmodified lines | ||
| 978 | 908 | |
| 979 | 909 | const created = yield* client.executions.create({ |
| 980 | 910 | path: { |
| 981 | − workspaceId: installation.workspaceId, | |
| 911 | + workspaceId: installation.scopeId, | |
| 982 | 912 | }, |
| 983 | 913 | payload: { |
| 984 | 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 | 926 | const approved = yield* client.executions.resume({ |
| 997 | 927 | path: { |
| 998 | − workspaceId: installation.workspaceId, | |
| 928 | + workspaceId: installation.scopeId, | |
| 999 | 929 | executionId: created.execution.id, |
| 1000 | 930 | }, |
| 1001 | 931 | payload: { |
| @@ -1018,7 +948,7 @@ describe("local-executor-server", () => { · 16 unmodified lines | ||
| 1018 | 948 | |
| 1019 | 949 | const resumed = yield* client.executions.resume({ |
| 1020 | 950 | path: { |
| 1021 | − workspaceId: installation.workspaceId, | |
| 951 | + workspaceId: installation.scopeId, | |
| 1022 | 952 | executionId: created.execution.id, |
| 1023 | 953 | }, |
| 1024 | 954 | payload: { |
| @@ -1057,12 +987,12 @@ describe("local-executor-server", () => { · 32 unmodified lines | ||
| 1057 | 987 | const installation = yield* bootstrapClient.local.installation({}); |
| 1058 | 988 | const client = yield* createExecutorApiClient({ |
| 1059 | 989 | baseUrl: server.baseUrl, |
| 1060 | − accountId: installation.accountId, | |
| 990 | + accountId: installation.actorScopeId, | |
| 1061 | 991 | }); |
| 1062 | 992 | |
| 1063 | 993 | yield* client.sources.create({ |
| 1064 | 994 | path: { |
| 1065 | − workspaceId: installation.workspaceId, | |
| 995 | + workspaceId: installation.scopeId, | |
| 1066 | 996 | }, |
| 1067 | 997 | payload: { |
| 1068 | 998 | name: "Demo", |
| @@ -1085,7 +1015,7 @@ describe("local-executor-server", () => { · 16 unmodified lines | ||
| 1085 | 1015 | for (const value of ["first", "second"]) { |
| 1086 | 1016 | const created = yield* client.executions.create({ |
| 1087 | 1017 | path: { |
| 1088 | − workspaceId: installation.workspaceId, | |
| 1018 | + workspaceId: installation.scopeId, | |
| 1089 | 1019 | }, |
| 1090 | 1020 | payload: { |
| 1091 | 1021 | code: `return await tools.demo.gated_echo({ value: "${value}" });`, |
| @@ -1098,7 +1028,7 @@ describe("local-executor-server", () => { · 6 unmodified lines | ||
| 1098 | 1028 | |
| 1099 | 1029 | const approved = yield* client.executions.resume({ |
| 1100 | 1030 | path: { |
| 1101 | − workspaceId: installation.workspaceId, | |
| 1031 | + workspaceId: installation.scopeId, | |
| 1102 | 1032 | executionId: created.execution.id, |
| 1103 | 1033 | }, |
| 1104 | 1034 | payload: { |
| @@ -1121,7 +1051,7 @@ describe("local-executor-server", () => { · 16 unmodified lines | ||
| 1121 | 1051 | |
| 1122 | 1052 | const resumed = yield* client.executions.resume({ |
| 1123 | 1053 | path: { |
| 1124 | − workspaceId: installation.workspaceId, | |
| 1054 | + workspaceId: installation.scopeId, | |
| 1125 | 1055 | executionId: created.execution.id, |
| 1126 | 1056 | }, |
| 1127 | 1057 | payload: { |
| @@ -1160,12 +1090,12 @@ describe("local-executor-server", () => { · 32 unmodified lines | ||
| 1160 | 1090 | const installation = yield* bootstrapClient.local.installation({}); |
| 1161 | 1091 | const client = yield* createExecutorApiClient({ |
| 1162 | 1092 | baseUrl: server.baseUrl, |
| 1163 | − accountId: installation.accountId, | |
| 1093 | + accountId: installation.actorScopeId, | |
| 1164 | 1094 | }); |
| 1165 | 1095 | |
| 1166 | 1096 | const existing = yield* client.sources.create({ |
| 1167 | 1097 | path: { |
| 1168 | − workspaceId: installation.workspaceId, | |
| 1098 | + workspaceId: installation.scopeId, | |
| 1169 | 1099 | }, |
| 1170 | 1100 | payload: { |
| 1171 | 1101 | name: "Demo", |
| @@ -1187,7 +1117,7 @@ describe("local-executor-server", () => { · 15 unmodified lines | ||
| 1187 | 1117 | |
| 1188 | 1118 | const seeded = yield* seedDemoMcpSourceInWorkspace({ |
| 1189 | 1119 | client, |
| 1190 | − workspaceId: installation.workspaceId, | |
| 1120 | + workspaceId: installation.scopeId, | |
| 1191 | 1121 | endpoint: demoServer.endpoint, |
| 1192 | 1122 | name: "Demo", |
| 1193 | 1123 | namespace: "demo", |
| @@ -1198,7 +1128,7 @@ describe("local-executor-server", () => { · 4 unmodified lines | ||
| 1198 | 1128 | |
| 1199 | 1129 | const sources = yield* client.sources.list({ |
| 1200 | 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 | 1179 | const installation = yield* bootstrapClient.local.installation({}); |
| 1250 | 1180 | const client = yield* createExecutorApiClient({ |
| 1251 | 1181 | baseUrl: server.baseUrl, |
| 1252 | − accountId: installation.accountId, | |
| 1182 | + accountId: installation.actorScopeId, | |
| 1253 | 1183 | }); |
| 1254 | 1184 | |
| 1255 | 1185 | yield* seedGithubOpenApiSourceInWorkspace({ |
| 1256 | 1186 | client, |
| 1257 | − workspaceId: installation.workspaceId, | |
| 1187 | + workspaceId: installation.scopeId, | |
| 1258 | 1188 | endpoint: openApiServer.baseUrl, |
| 1259 | 1189 | specUrl: openApiServer.specUrl, |
| 1260 | 1190 | name: "GitHub", |
| @@ -1263,7 +1193,7 @@ describe("local-executor-server", () => { · 2 unmodified lines | ||
| 1263 | 1193 | |
| 1264 | 1194 | const execution = yield* client.executions.create({ |
| 1265 | 1195 | path: { |
| 1266 | − workspaceId: installation.workspaceId, | |
| 1196 | + workspaceId: installation.scopeId, | |
| 1267 | 1197 | }, |
| 1268 | 1198 | payload: { |
| 1269 | 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 | 1218 | const connected = yield* client.sources.connect({ |
| 1289 | 1219 | path: { |
| 1290 | − workspaceId: installation.workspaceId, | |
| 1220 | + workspaceId: installation.scopeId, | |
| 1291 | 1221 | }, |
| 1292 | 1222 | payload: { |
| 1293 | 1223 | kind: "openapi", |
| @@ -1309,7 +1239,7 @@ describe("local-executor-server", () => { · 15 unmodified lines | ||
| 1309 | 1239 | |
| 1310 | 1240 | const sources = yield* client.sources.list({ |
| 1311 | 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 | 1249 | const execution = yield* client.executions.create({ |
| 1320 | 1250 | path: { |
| 1321 | − workspaceId: installation.workspaceId, | |
| 1251 | + workspaceId: installation.scopeId, | |
| 1322 | 1252 | }, |
| 1323 | 1253 | payload: { |
| 1324 | 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 | 1274 | const connected = yield* client.sources.connect({ |
| 1345 | 1275 | path: { |
| 1346 | − workspaceId: installation.workspaceId, | |
| 1276 | + workspaceId: installation.scopeId, | |
| 1347 | 1277 | }, |
| 1348 | 1278 | payload: { |
| 1349 | 1279 | kind: "mcp", |
| @@ -1361,7 +1291,7 @@ describe("local-executor-server", () => { · 11 unmodified lines | ||
| 1361 | 1291 | |
| 1362 | 1292 | const execution = yield* client.executions.create({ |
| 1363 | 1293 | path: { |
| 1364 | − workspaceId: installation.workspaceId, | |
| 1294 | + workspaceId: installation.scopeId, | |
| 1365 | 1295 | }, |
| 1366 | 1296 | payload: { |
| 1367 | 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 | 1310 | const approved = yield* client.executions.resume({ |
| 1381 | 1311 | path: { |
| 1382 | − workspaceId: installation.workspaceId, | |
| 1312 | + workspaceId: installation.scopeId, | |
| 1383 | 1313 | executionId: execution.execution.id, |
| 1384 | 1314 | }, |
| 1385 | 1315 | payload: { |
| @@ -1405,7 +1335,7 @@ describe("local-executor-server", () => { · 19 unmodified lines | ||
| 1405 | 1335 | |
| 1406 | 1336 | const resumed = yield* client.executions.resume({ |
| 1407 | 1337 | path: { |
| 1408 | − workspaceId: installation.workspaceId, | |
| 1338 | + workspaceId: installation.scopeId, | |
| 1409 | 1339 | executionId: execution.execution.id, |
| 1410 | 1340 | }, |
| 1411 | 1341 | payload: { |
| @@ -1436,7 +1366,7 @@ describe("local-executor-server", () => { · 24 unmodified lines | ||
| 1436 | 1366 | |
| 1437 | 1367 | const connected = yield* client.sources.connect({ |
| 1438 | 1368 | path: { |
| 1439 | − workspaceId: installation.workspaceId, | |
| 1369 | + workspaceId: installation.scopeId, | |
| 1440 | 1370 | }, |
| 1441 | 1371 | payload: { |
| 1442 | 1372 | kind: "mcp", |
| @@ -1463,7 +1393,7 @@ describe("local-executor-server", () => { · 20 unmodified lines | ||
| 1463 | 1393 | |
| 1464 | 1394 | const refreshedSource = yield* client.sources.get({ |
| 1465 | 1395 | path: { |
| 1466 | − workspaceId: installation.workspaceId, | |
| 1396 | + workspaceId: installation.scopeId, | |
| 1467 | 1397 | sourceId: connected.source.id, |
| 1468 | 1398 | }, |
| 1469 | 1399 | }); |
| @@ -1474,7 +1404,7 @@ describe("local-executor-server", () => { · 4 unmodified lines | ||
| 1474 | 1404 | |
| 1475 | 1405 | const toolCall = yield* client.executions.create({ |
| 1476 | 1406 | path: { |
| 1477 | − workspaceId: installation.workspaceId, | |
| 1407 | + workspaceId: installation.scopeId, | |
| 1478 | 1408 | }, |
| 1479 | 1409 | payload: { |
| 1480 | 1410 | code: "return await tools.axiom.whoami({});", |
| @@ -1491,7 +1421,7 @@ describe("local-executor-server", () => { · 10 unmodified lines | ||
| 1491 | 1421 | |
| 1492 | 1422 | const approvedToolCall = yield* client.executions.resume({ |
| 1493 | 1423 | path: { |
| 1494 | − workspaceId: installation.workspaceId, | |
| 1424 | + workspaceId: installation.scopeId, | |
| 1495 | 1425 | executionId: toolCall.execution.id, |
| 1496 | 1426 | }, |
| 1497 | 1427 | payload: { |
| @@ -1529,12 +1459,12 @@ describe("local-executor-server", () => { · 31 unmodified lines | ||
| 1529 | 1459 | const installation = yield* bootstrapClient.local.installation({}); |
| 1530 | 1460 | const client = yield* createExecutorApiClient({ |
| 1531 | 1461 | baseUrl: server.baseUrl, |
| 1532 | − accountId: installation.accountId, | |
| 1462 | + accountId: installation.actorScopeId, | |
| 1533 | 1463 | }); |
| 1534 | 1464 | |
| 1535 | 1465 | const added = yield* client.executions.create({ |
| 1536 | 1466 | path: { |
| 1537 | − workspaceId: installation.workspaceId, | |
| 1467 | + workspaceId: installation.scopeId, | |
| 1538 | 1468 | }, |
| 1539 | 1469 | payload: { |
| 1540 | 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 | 1493 | while (true) { |
| 1564 | 1494 | const sources = yield* client.sources.list({ |
| 1565 | 1495 | path: { |
| 1566 | − workspaceId: installation.workspaceId, | |
| 1496 | + workspaceId: installation.scopeId, | |
| 1567 | 1497 | }, |
| 1568 | 1498 | }); |
| 1569 | 1499 | const source = sources.find((entry) => entry.namespace === "axiom"); |
| @@ -1581,7 +1511,7 @@ describe("local-executor-server", () => { · 11 unmodified lines | ||
| 1581 | 1511 | |
| 1582 | 1512 | const toolCall = yield* client.executions.create({ |
| 1583 | 1513 | path: { |
| 1584 | − workspaceId: installation.workspaceId, | |
| 1514 | + workspaceId: installation.scopeId, | |
| 1585 | 1515 | }, |
| 1586 | 1516 | payload: { |
| 1587 | 1517 | code: "return await tools.axiom.whoami({});", |
| @@ -1597,7 +1527,7 @@ describe("local-executor-server", () => { · 9 unmodified lines | ||
| 1597 | 1527 | |
| 1598 | 1528 | const approvedToolCall = yield* client.executions.resume({ |
| 1599 | 1529 | path: { |
| 1600 | − workspaceId: installation.workspaceId, | |
| 1530 | + workspaceId: installation.scopeId, | |
| 1601 | 1531 | executionId: toolCall.execution.id, |
| 1602 | 1532 | }, |
| 1603 | 1533 | payload: { |
| @@ -1633,12 +1563,12 @@ describe("local-executor-server", () => { · 29 unmodified lines | ||
| 1633 | 1563 | const installation = yield* bootstrapClient.local.installation({}); |
| 1634 | 1564 | const client = yield* createExecutorApiClient({ |
| 1635 | 1565 | baseUrl: server.baseUrl, |
| 1636 | − accountId: installation.accountId, | |
| 1566 | + accountId: installation.actorScopeId, | |
| 1637 | 1567 | }); |
| 1638 | 1568 | |
| 1639 | 1569 | const connected = yield* client.sources.connect({ |
| 1640 | 1570 | path: { |
| 1641 | − workspaceId: installation.workspaceId, | |
| 1571 | + workspaceId: installation.scopeId, | |
| 1642 | 1572 | }, |
| 1643 | 1573 | payload: { |
| 1644 | 1574 | kind: "openapi", |
| @@ -1655,7 +1585,7 @@ describe("local-executor-server", () => { · 10 unmodified lines | ||
| 1655 | 1585 | |
| 1656 | 1586 | const gated = yield* client.executions.create({ |
| 1657 | 1587 | path: { |
| 1658 | − workspaceId: installation.workspaceId, | |
| 1588 | + workspaceId: installation.scopeId, | |
| 1659 | 1589 | }, |
| 1660 | 1590 | payload: { |
| 1661 | 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 | 1598 | throw new Error("Expected pending approval interaction"); |
| 1669 | 1599 | } |
| 1670 | 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 | 1602 | expect(gated.pendingInteraction.payloadJson).toContain("\"approve\""); |
| 1673 | 1603 | |
| 1674 | 1604 | const approved = yield* client.executions.resume({ |
| 1675 | 1605 | path: { |
| 1676 | − workspaceId: installation.workspaceId, | |
| 1606 | + workspaceId: installation.scopeId, | |
| 1677 | 1607 | executionId: gated.execution.id, |
| 1678 | 1608 | }, |
| 1679 | 1609 | payload: { |
| @@ -1691,7 +1621,7 @@ describe("local-executor-server", () => { · 11 unmodified lines | ||
| 1691 | 1621 | |
| 1692 | 1622 | const policy = yield* client.policies.create({ |
| 1693 | 1623 | path: { |
| 1694 | − workspaceId: installation.workspaceId, | |
| 1624 | + workspaceId: installation.scopeId, | |
| 1695 | 1625 | }, |
| 1696 | 1626 | payload: { |
| 1697 | 1627 | resourcePattern: "dns.records.createRecord", |
| @@ -1703,7 +1633,7 @@ describe("local-executor-server", () => { · 5 unmodified lines | ||
| 1703 | 1633 | |
| 1704 | 1634 | const automatic = yield* client.executions.create({ |
| 1705 | 1635 | path: { |
| 1706 | − workspaceId: installation.workspaceId, | |
| 1636 | + workspaceId: installation.scopeId, | |
| 1707 | 1637 | }, |
| 1708 | 1638 | payload: { |
| 1709 | 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 | 1665 | const installation = yield* bootstrapClient.local.installation({}); |
| 1736 | 1666 | |
| 1737 | 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 | 1669 | method: "POST", |
| 1740 | 1670 | headers: { |
| 1741 | 1671 | "content-type": "application/json", |
| 1742 | − "x-executor-account-id": installation.accountId, | |
| 1672 | + "x-executor-account-id": installation.actorScopeId, | |
| 1743 | 1673 | }, |
| 1744 | 1674 | body: JSON.stringify({ |
| 1745 | 1675 | provider: "mcp", |
| @@ -1774,11 +1704,11 @@ describe("local-executor-server", () => { · 28 unmodified lines | ||
| 1774 | 1704 | |
| 1775 | 1705 | const client = yield* createExecutorApiClient({ |
| 1776 | 1706 | baseUrl: server.baseUrl, |
| 1777 | − accountId: installation.accountId, | |
| 1707 | + accountId: installation.actorScopeId, | |
| 1778 | 1708 | }); |
| 1779 | 1709 | const sources = yield* client.sources.list({ |
| 1780 | 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 | 1734 | const installation = yield* bootstrapClient.local.installation({}); |
| 1805 | 1735 | const client = yield* createExecutorApiClient({ |
| 1806 | 1736 | baseUrl: server.baseUrl, |
| 1807 | − accountId: installation.accountId, | |
| 1737 | + accountId: installation.actorScopeId, | |
| 1808 | 1738 | }); |
| 1809 | 1739 | yield* writeConfiguredLocalMcpSource({ |
| 1810 | 1740 | workspaceRoot: server.workspaceRoot, |
| @@ -1816,7 +1746,7 @@ describe("local-executor-server", () => { · 5 unmodified lines | ||
| 1816 | 1746 | |
| 1817 | 1747 | const execution = yield* client.executions.create({ |
| 1818 | 1748 | path: { |
| 1819 | − workspaceId: installation.workspaceId, | |
| 1749 | + workspaceId: installation.scopeId, | |
| 1820 | 1750 | }, |
| 1821 | 1751 | payload: { |
| 1822 | 1752 | code: 'return await tools.demo.gated_echo({ value: "broken" });', |
| @@ -1832,7 +1762,7 @@ describe("local-executor-server", () => { · 9 unmodified lines | ||
| 1832 | 1762 | |
| 1833 | 1763 | const resumed = yield* client.executions.resume({ |
| 1834 | 1764 | path: { |
| 1835 | − workspaceId: installation.workspaceId, | |
| 1765 | + workspaceId: installation.scopeId, | |
| 1836 | 1766 | executionId: execution.execution.id, |
| 1837 | 1767 | }, |
| 1838 | 1768 | payload: { |
| @@ -484,7 +484,7 @@ const buildConnectPayload = (form: ConnectFormState): ConnectSourcePayload => { · 483 unmodified lines | ||
| 484 | 484 | discoveryUrl: trimToNull(form.discoveryUrl), |
| 485 | 485 | name: trimToNull(form.name), |
| 486 | 486 | namespace: trimToNull(form.namespace), |
| 487 | − workspaceOauthClientId: | |
| 487 | + scopeOauthClientId: | |
| 488 | 488 | form.authKind === "oauth2" && |
| 489 | 489 | form.workspaceOauthClientId.trim().length > 0 |
| 490 | 490 | ? form.workspaceOauthClientId.trim() |
| @@ -1114,7 +1114,7 @@ export function AddSourcePage() { · 623 unmodified lines | ||
| 1114 | 1114 | selectedGoogleTemplateIds.includes(template.id), |
| 1115 | 1115 | ); |
| 1116 | 1116 | const payload: ConnectSourceBatchPayload = { |
| 1117 | − workspaceOauthClientId: | |
| 1117 | + scopeOauthClientId: | |
| 1118 | 1118 | workspaceOauthClientId as WorkspaceOauthClient["id"], |
| 1119 | 1119 | sources: selectedTemplates.map((template) => ({ |
| 1120 | 1120 | service: template.service, |
| @@ -36,6 +36,7 @@ · 35 unmodified lines | ||
| 36 | 36 | }, |
| 37 | 37 | "devDependencies": { |
| 38 | 38 | "@effect/vitest": "catalog:", |
| 39 | + "@executor/effect-test-utils": "workspace:*", | |
| 39 | 40 | "@executor/mcp-elicitation-demo": "workspace:*", |
| 40 | 41 | "@executor/runtime-ses": "workspace:*", |
| 41 | 42 | "@modelcontextprotocol/sdk": "^1.26.0", |
| @@ -150,6 +151,7 @@ · 108 unmodified lines | ||
| 150 | 151 | "@effect/platform": "catalog:", |
| 151 | 152 | "@effect/platform-node": "catalog:", |
| 152 | 153 | "@effect/vitest": "catalog:", |
| 154 | + "@executor/effect-test-utils": "workspace:*", | |
| 153 | 155 | "@executor/platform-sdk-file": "workspace:*", |
| 154 | 156 | "@types/jsdom": "^21.1.7", |
| 155 | 157 | "@types/node": "catalog:", |
| @@ -164,6 +166,20 @@ · 8 unmodified lines | ||
| 164 | 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 | 183 | "packages/dev/kitchen-sink": { |
| 168 | 184 | "name": "@executor/kitchen-sink", |
| 169 | 185 | "version": "0.0.0", |
| @@ -337,6 +353,7 @@ · 167 unmodified lines | ||
| 337 | 353 | }, |
| 338 | 354 | "devDependencies": { |
| 339 | 355 | "@effect/vitest": "catalog:", |
| 356 | + "@executor/effect-test-utils": "workspace:*", | |
| 340 | 357 | "@modelcontextprotocol/sdk": "^1.26.0", |
| 341 | 358 | "@types/node": "catalog:", |
| 342 | 359 | "bun-types": "catalog:", |
| @@ -709,6 +726,8 @@ · 366 unmodified lines | ||
| 709 | 726 | |
| 710 | 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 | 731 | "@executor/executor-mcp": ["@executor/executor-mcp@workspace:packages/hosts/mcp"], |
| 713 | 732 | |
| 714 | 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 | 6 | const executor = await createSqliteExecutor({ |
| 7 | 7 | databasePath, |
| 8 | − workspaceName: "SQLite Example Workspace", | |
| 9 | − workspaceRoot: process.cwd(), | |
| 8 | + scopeName: "SQLite Example Workspace", | |
| 9 | + scopeRoot: process.cwd(), | |
| 10 | 10 | }); |
| 11 | 11 | |
| 12 | 12 | try { |
| @@ -16,13 +16,13 @@ import { · 15 unmodified lines | ||
| 16 | 16 | type ExecutorSecretMaterialBackend, |
| 17 | 17 | type ExecutorSourceArtifactBackend, |
| 18 | 18 | type ExecutorSourceTypeDeclarationsBackend, |
| 19 | − type ExecutorWorkspaceConfigBackend, | |
| 20 | − type ExecutorWorkspaceStateBackend, | |
| 19 | + type ExecutorScopeConfigBackend, | |
| 20 | + type ExecutorScopeStateBackend, | |
| 21 | 21 | } from "@executor/platform-sdk"; |
| 22 | 22 | import type { ExecutorRuntimeOptions } from "@executor/platform-sdk/runtime"; |
| 23 | 23 | import { |
| 24 | 24 | type AuthArtifact, |
| 25 | − AccountIdSchema, | |
| 25 | + ScopeIdSchema, | |
| 26 | 26 | AuthArtifactSchema, |
| 27 | 27 | type AuthLease, |
| 28 | 28 | AuthLeaseSchema, |
| @@ -43,11 +43,10 @@ import { · 14 unmodified lines | ||
| 43 | 43 | SourceAuthSessionSchema, |
| 44 | 44 | SourceCatalogIdSchema, |
| 45 | 45 | SourceCatalogRevisionIdSchema, |
| 46 | − WorkspaceIdSchema, | |
| 47 | − type WorkspaceOauthClient, | |
| 48 | − WorkspaceOauthClientSchema, | |
| 49 | − type WorkspaceSourceOauthClient, | |
| 50 | − WorkspaceSourceOauthClientSchema, | |
| 46 | + type ScopeOauthClient, | |
| 47 | + ScopeOauthClientSchema, | |
| 48 | + type ScopedSourceOauthClient, | |
| 49 | + ScopedSourceOauthClientSchema, | |
| 51 | 50 | type SecretMaterial, |
| 52 | 51 | type SecretRef, |
| 53 | 52 | } from "@executor/platform-sdk/schema"; |
| @@ -59,24 +58,24 @@ import { contentHash, snapshotFromSourceCatalogSyncResult } from "@executor/sour · 5 unmodified lines | ||
| 59 | 58 | |
| 60 | 59 | export type CreateSqliteExecutorBackendOptions = { |
| 61 | 60 | databasePath?: string; |
| 62 | − workspaceName?: string; | |
| 63 | − workspaceRoot?: string | null; | |
| 64 | − workspaceId?: string; | |
| 65 | − accountId?: string; | |
| 61 | + scopeName?: string; | |
| 62 | + scopeRoot?: string | null; | |
| 63 | + scopeId?: string; | |
| 64 | + actorScopeId?: string; | |
| 66 | 65 | }; |
| 67 | 66 | |
| 68 | 67 | type DocumentNamespace = |
| 69 | 68 | | "installation" |
| 70 | − | "workspace_config" | |
| 71 | − | "workspace_state" | |
| 69 | + | "scope_config" | |
| 70 | + | "scope_state" | |
| 72 | 71 | | "source_artifact" |
| 73 | 72 | | "executor_state"; |
| 74 | 73 | |
| 75 | 74 | type ExecutorStateCollections = { |
| 76 | 75 | authArtifacts: readonly AuthArtifact[]; |
| 77 | 76 | authLeases: readonly AuthLease[]; |
| 78 | − sourceOauthClients: readonly WorkspaceSourceOauthClient[]; | |
| 79 | − workspaceOauthClients: readonly WorkspaceOauthClient[]; | |
| 77 | + sourceOauthClients: readonly ScopedSourceOauthClient[]; | |
| 78 | + scopeOauthClients: readonly ScopeOauthClient[]; | |
| 80 | 79 | providerAuthGrants: readonly ProviderAuthGrant[]; |
| 81 | 80 | sourceAuthSessions: readonly SourceAuthSession[]; |
| 82 | 81 | secretMaterials: readonly SecretMaterial[]; |
| @@ -90,10 +89,10 @@ const decodeConfig = Schema.decodeUnknownSync(LocalExecutorConfigSchema); · 7 unmodified lines | ||
| 90 | 89 | const decodeAuthArtifacts = Schema.decodeUnknownSync(Schema.Array(AuthArtifactSchema)); |
| 91 | 90 | const decodeAuthLeases = Schema.decodeUnknownSync(Schema.Array(AuthLeaseSchema)); |
| 92 | 91 | const decodeSourceOauthClients = Schema.decodeUnknownSync( |
| 93 | − Schema.Array(WorkspaceSourceOauthClientSchema), | |
| 92 | + Schema.Array(ScopedSourceOauthClientSchema), | |
| 94 | 93 | ); |
| 95 | −const decodeWorkspaceOauthClients = Schema.decodeUnknownSync( | |
| 96 | − Schema.Array(WorkspaceOauthClientSchema), | |
| 94 | +const decodeScopeOauthClients = Schema.decodeUnknownSync( | |
| 95 | + Schema.Array(ScopeOauthClientSchema), | |
| 97 | 96 | ); |
| 98 | 97 | const decodeProviderAuthGrants = Schema.decodeUnknownSync( |
| 99 | 98 | Schema.Array(ProviderAuthGrantSchema), |
| @@ -117,10 +116,10 @@ type SourceArtifactBuildInput = Parameters<ExecutorSourceArtifactBackend["build" · 17 unmodified lines | ||
| 117 | 116 | |
| 118 | 117 | const SQLITE_SECRET_PROVIDER_ID = "sqlite"; |
| 119 | 118 | |
| 120 | −type WorkspaceState = Parameters<ExecutorWorkspaceStateBackend["write"]>[0]; | |
| 119 | +type ScopeState = Parameters<ExecutorScopeStateBackend["write"]>[0]; | |
| 121 | 120 | const defaultProjectConfig = decodeConfig({}); |
| 122 | 121 | |
| 123 | −const defaultWorkspaceState = (): WorkspaceState => ({ | |
| 122 | +const defaultScopeState = (): ScopeState => ({ | |
| 124 | 123 | version: 1 as const, |
| 125 | 124 | sources: {}, |
| 126 | 125 | policies: {}, |
| @@ -258,8 +257,12 @@ const createInstallationStore = ( · 131 unmodified lines | ||
| 258 | 257 | ): ExecutorInstallationBackend => { |
| 259 | 258 | const provision = (): LocalInstallation => |
| 260 | 259 | decodeInstallation({ |
| 261 | − accountId: AccountIdSchema.make(options.accountId ?? "acct_sqlite_example"), | |
| 262 | − workspaceId: WorkspaceIdSchema.make(options.workspaceId ?? "ws_sqlite_example"), | |
| 260 | + actorScopeId: ScopeIdSchema.make(options.actorScopeId ?? "acct_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 | 268 | return { |
| @@ -276,13 +279,13 @@ const createInstallationStore = ( · 10 unmodified lines | ||
| 276 | 279 | }; |
| 277 | 280 | }; |
| 278 | 281 | |
| 279 | −const createWorkspaceConfigStore = ( | |
| 282 | +const createScopeConfigStore = ( | |
| 280 | 283 | store: SqliteDocumentStore, |
| 281 | −): ExecutorWorkspaceConfigBackend => ({ | |
| 284 | +): ExecutorScopeConfigBackend => ({ | |
| 282 | 285 | load: () => |
| 283 | 286 | effectTry("load workspace config", () => { |
| 284 | 287 | const projectConfig = store.read( |
| 285 | − "workspace_config", | |
| 288 | + "scope_config", | |
| 286 | 289 | "project", |
| 287 | 290 | decodeConfig, |
| 288 | 291 | () => defaultProjectConfig, |
| @@ -296,22 +299,22 @@ const createWorkspaceConfigStore = ( · 7 unmodified lines | ||
| 296 | 299 | }), |
| 297 | 300 | writeProject: (config) => |
| 298 | 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 }) => | |
| 302 | − resolvePath(workspaceRoot, path), | |
| 304 | + resolveRelativePath: ({ path, scopeRoot }) => | |
| 305 | + resolvePath(scopeRoot, path), | |
| 303 | 306 | }); |
| 304 | 307 | |
| 305 | −const createWorkspaceStateStore = ( | |
| 308 | +const createScopeStateStore = ( | |
| 306 | 309 | store: SqliteDocumentStore, |
| 307 | −): ExecutorWorkspaceStateBackend => ({ | |
| 310 | +): ExecutorScopeStateBackend => ({ | |
| 308 | 311 | load: () => |
| 309 | 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 | 315 | write: (state) => |
| 313 | 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 | 354 | return store.read("executor_state", key, decodeAuthLeases, () => []) as ExecutorStateCollections[K]; |
| 352 | 355 | case "sourceOauthClients": |
| 353 | 356 | return store.read("executor_state", key, decodeSourceOauthClients, () => []) as ExecutorStateCollections[K]; |
| 354 | − case "workspaceOauthClients": | |
| 355 | − return store.read("executor_state", key, decodeWorkspaceOauthClients, () => []) as ExecutorStateCollections[K]; | |
| 357 | + case "scopeOauthClients": | |
| 358 | + return store.read("executor_state", key, decodeScopeOauthClients, () => []) as ExecutorStateCollections[K]; | |
| 356 | 359 | case "providerAuthGrants": |
| 357 | 360 | return store.read("executor_state", key, decodeProviderAuthGrants, () => []) as ExecutorStateCollections[K]; |
| 358 | 361 | case "sourceAuthSessions": |
| @@ -387,23 +390,23 @@ const createExecutorStateStore = ( · 28 unmodified lines | ||
| 387 | 390 | |
| 388 | 391 | return { |
| 389 | 392 | authArtifacts: { |
| 390 | − listByWorkspaceId: (workspaceId) => | |
| 393 | + listByScopeId: (scopeId) => | |
| 391 | 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 | 398 | effectTry("list auth artifacts by source", () => |
| 396 | 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 | 404 | effectTry("get auth artifact", () => |
| 402 | 405 | Option.fromNullable( |
| 403 | 406 | readCollection("authArtifacts").find((item) => |
| 404 | − item.workspaceId === workspaceId | |
| 407 | + item.scopeId === scopeId | |
| 405 | 408 | && item.sourceId === sourceId |
| 406 | − && sameActor(item.actorAccountId, actorAccountId) | |
| 409 | + && sameActor(item.actorScopeId, actorScopeId) | |
| 407 | 410 | && item.slot === slot |
| 408 | 411 | ), |
| 409 | 412 | ), |
| @@ -412,9 +415,9 @@ const createExecutorStateStore = ( · 2 unmodified lines | ||
| 412 | 415 | effectTry("upsert auth artifact", () => { |
| 413 | 416 | updateCollection("authArtifacts", (items) => { |
| 414 | 417 | const index = items.findIndex((item) => |
| 415 | − item.workspaceId === artifact.workspaceId | |
| 418 | + item.scopeId === artifact.scopeId | |
| 416 | 419 | && item.sourceId === artifact.sourceId |
| 417 | − && sameActor(item.actorAccountId, artifact.actorAccountId) | |
| 420 | + && sameActor(item.actorScopeId, artifact.actorScopeId) | |
| 418 | 421 | && item.slot === artifact.slot |
| 419 | 422 | ); |
| 420 | 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 | 431 | effectTry("remove auth artifact", () => |
| 429 | 432 | updateCollection("authArtifacts", (items) => { |
| 430 | 433 | const before = items.length; |
| 431 | 434 | const remaining = items.filter((item) => !( |
| 432 | − item.workspaceId === workspaceId | |
| 435 | + item.scopeId === scopeId | |
| 433 | 436 | && item.sourceId === sourceId |
| 434 | − && sameActor(item.actorAccountId, actorAccountId) | |
| 437 | + && sameActor(item.actorScopeId, actorScopeId) | |
| 435 | 438 | && (slot === undefined || item.slot === slot) |
| 436 | 439 | )); |
| 437 | 440 | items.splice(0, items.length, ...remaining); |
| 438 | 441 | return before !== remaining.length; |
| 439 | 442 | }), |
| 440 | 443 | ), |
| 441 | − removeByWorkspaceAndSourceId: ({ workspaceId, sourceId }) => | |
| 444 | + removeByScopeAndSourceId: ({ scopeId, sourceId }) => | |
| 442 | 445 | effectTry("remove auth artifacts by source", () => |
| 443 | 446 | updateCollection("authArtifacts", (items) => { |
| 444 | 447 | const remaining = items.filter((item) => |
| 445 | − !(item.workspaceId === workspaceId && item.sourceId === sourceId) | |
| 448 | + !(item.scopeId === scopeId && item.sourceId === sourceId) | |
| 446 | 449 | ); |
| 447 | 450 | const removed = items.length - remaining.length; |
| 448 | 451 | items.splice(0, items.length, ...remaining); |
| @@ -481,11 +484,11 @@ const createExecutorStateStore = ( · 32 unmodified lines | ||
| 481 | 484 | ), |
| 482 | 485 | }, |
| 483 | 486 | sourceOauthClients: { |
| 484 | − getByWorkspaceSourceAndProvider: ({ workspaceId, sourceId, providerKey }) => | |
| 487 | + getByScopeSourceAndProvider: ({ scopeId, sourceId, providerKey }) => | |
| 485 | 488 | effectTry("get source oauth client", () => |
| 486 | 489 | Option.fromNullable( |
| 487 | 490 | readCollection("sourceOauthClients").find((item) => |
| 488 | − item.workspaceId === workspaceId | |
| 491 | + item.scopeId === scopeId | |
| 489 | 492 | && item.sourceId === sourceId |
| 490 | 493 | && item.providerKey === providerKey |
| 491 | 494 | ), |
| @@ -495,7 +498,7 @@ const createExecutorStateStore = ( · 3 unmodified lines | ||
| 495 | 498 | effectTry("upsert source oauth client", () => { |
| 496 | 499 | updateCollection("sourceOauthClients", (items) => { |
| 497 | 500 | const index = items.findIndex((item) => |
| 498 | − item.workspaceId === oauthClient.workspaceId | |
| 501 | + item.scopeId === oauthClient.scopeId | |
| 499 | 502 | && item.sourceId === oauthClient.sourceId |
| 500 | 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 | 513 | effectTry("remove source oauth clients", () => |
| 511 | 514 | updateCollection("sourceOauthClients", (items) => { |
| 512 | 515 | const remaining = items.filter((item) => |
| 513 | − !(item.workspaceId === workspaceId && item.sourceId === sourceId) | |
| 516 | + !(item.scopeId === scopeId && item.sourceId === sourceId) | |
| 514 | 517 | ); |
| 515 | 518 | const removed = items.length - remaining.length; |
| 516 | 519 | items.splice(0, items.length, ...remaining); |
| @@ -518,22 +521,22 @@ const createExecutorStateStore = ( · 1 unmodified line | ||
| 518 | 521 | }), |
| 519 | 522 | ), |
| 520 | 523 | }, |
| 521 | − workspaceOauthClients: { | |
| 522 | − listByWorkspaceAndProvider: ({ workspaceId, providerKey }) => | |
| 524 | + scopeOauthClients: { | |
| 525 | + listByScopeAndProvider: ({ scopeId, providerKey }) => | |
| 523 | 526 | effectTry("list workspace oauth clients", () => |
| 524 | − readCollection("workspaceOauthClients").filter((item) => | |
| 525 | − item.workspaceId === workspaceId && item.providerKey === providerKey | |
| 527 | + readCollection("scopeOauthClients").filter((item) => | |
| 528 | + item.scopeId === scopeId && item.providerKey === providerKey | |
| 526 | 529 | ), |
| 527 | 530 | ), |
| 528 | 531 | getById: (id) => |
| 529 | 532 | effectTry("get workspace oauth client", () => |
| 530 | 533 | Option.fromNullable( |
| 531 | − readCollection("workspaceOauthClients").find((item) => item.id === id), | |
| 534 | + readCollection("scopeOauthClients").find((item) => item.id === id), | |
| 532 | 535 | ), |
| 533 | 536 | ), |
| 534 | 537 | upsert: (oauthClient) => |
| 535 | 538 | effectTry("upsert workspace oauth client", () => { |
| 536 | − updateCollection("workspaceOauthClients", (items) => { | |
| 539 | + updateCollection("scopeOauthClients", (items) => { | |
| 537 | 540 | const index = items.findIndex((item) => item.id === oauthClient.id); |
| 538 | 541 | if (index >= 0) { |
| 539 | 542 | items[index] = oauthClient; |
| @@ -544,7 +547,7 @@ const createExecutorStateStore = ( · 4 unmodified lines | ||
| 544 | 547 | }), |
| 545 | 548 | removeById: (id) => |
| 546 | 549 | effectTry("remove workspace oauth client", () => |
| 547 | − updateCollection("workspaceOauthClients", (items) => { | |
| 550 | + updateCollection("scopeOauthClients", (items) => { | |
| 548 | 551 | const remaining = items.filter((item) => item.id !== id); |
| 549 | 552 | const removed = remaining.length !== items.length; |
| 550 | 553 | items.splice(0, items.length, ...remaining); |
| @@ -553,15 +556,15 @@ const createExecutorStateStore = ( · 2 unmodified lines | ||
| 553 | 556 | ), |
| 554 | 557 | }, |
| 555 | 558 | providerAuthGrants: { |
| 556 | − listByWorkspaceId: (workspaceId) => | |
| 559 | + listByScopeId: (scopeId) => | |
| 557 | 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 | 564 | effectTry("list provider grants by actor", () => |
| 562 | 565 | readCollection("providerAuthGrants").filter((item) => |
| 563 | − item.workspaceId === workspaceId | |
| 564 | − && item.actorAccountId === actorAccountId | |
| 566 | + item.scopeId === scopeId | |
| 567 | + && item.actorScopeId === actorScopeId | |
| 565 | 568 | && item.providerKey === providerKey |
| 566 | 569 | ), |
| 567 | 570 | ), |
| @@ -595,9 +598,9 @@ const createExecutorStateStore = ( · 27 unmodified lines | ||
| 595 | 598 | sourceAuthSessions: { |
| 596 | 599 | listAll: () => |
| 597 | 600 | effectTry("list source auth sessions", () => readCollection("sourceAuthSessions")), |
| 598 | − listByWorkspaceId: (workspaceId) => | |
| 601 | + listByScopeId: (scopeId) => | |
| 599 | 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 | 605 | getById: (id) => |
| 603 | 606 | effectTry("get source auth session", () => |
| @@ -611,13 +614,13 @@ const createExecutorStateStore = ( · 7 unmodified lines | ||
| 611 | 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 | 618 | effectTry("get pending source auth session", () => |
| 616 | 619 | Option.fromNullable( |
| 617 | 620 | readCollection("sourceAuthSessions").find((item) => |
| 618 | − item.workspaceId === workspaceId | |
| 621 | + item.scopeId === scopeId | |
| 619 | 622 | && item.sourceId === sourceId |
| 620 | − && item.actorAccountId === actorAccountId | |
| 623 | + && item.actorScopeId === actorScopeId | |
| 621 | 624 | && item.status === "pending" |
| 622 | 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 | 663 | effectTry("remove source auth sessions", () => |
| 661 | 664 | updateCollection("sourceAuthSessions", (items) => { |
| 662 | 665 | const remaining = items.filter((item) => |
| 663 | − !(item.workspaceId === workspaceId && item.sourceId === sourceId) | |
| 666 | + !(item.scopeId === scopeId && item.sourceId === sourceId) | |
| 664 | 667 | ); |
| 665 | 668 | const removed = remaining.length !== items.length; |
| 666 | 669 | items.splice(0, items.length, ...remaining); |
| @@ -739,11 +742,11 @@ const createExecutorStateStore = ( · 72 unmodified lines | ||
| 739 | 742 | readCollection("executions").find((item) => item.id === executionId), |
| 740 | 743 | ), |
| 741 | 744 | ), |
| 742 | − getByWorkspaceAndId: (workspaceId, executionId) => | |
| 743 | − effectTry("get execution by workspace and id", () => | |
| 745 | + getByScopeAndId: (scopeId, executionId) => | |
| 746 | + effectTry("get execution by scope and id", () => | |
| 744 | 747 | Option.fromNullable( |
| 745 | 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 | 935 | const secretMaterial = createSecretMaterialBackend(executorState); |
| 933 | 936 | |
| 934 | 937 | return { |
| 935 | − workspace: { | |
| 936 | − workspaceName: options.workspaceName ?? "SQLite SDK Example", | |
| 937 | − workspaceRoot: options.workspaceRoot ?? null, | |
| 938 | + scope: { | |
| 939 | + scopeName: options.scopeName ?? "SQLite SDK Example", | |
| 940 | + scopeRoot: options.scopeRoot ?? null, | |
| 938 | 941 | metadata: { |
| 939 | 942 | kind: "sqlite", |
| 940 | 943 | databasePath, |
| @@ -942,8 +945,8 @@ export const createSqliteExecutorBackend = ( · 1 unmodified line | ||
| 942 | 945 | }, |
| 943 | 946 | storage: { |
| 944 | 947 | installation: createInstallationStore(store, options), |
| 945 | − workspaceConfig: createWorkspaceConfigStore(store), | |
| 946 | − workspaceState: createWorkspaceStateStore(store), | |
| 948 | + scopeConfig: createScopeConfigStore(store), | |
| 949 | + scopeState: createScopeStateStore(store), | |
| 947 | 950 | sourceArtifacts: createSourceArtifactStore(store), |
| 948 | 951 | executorState, |
| 949 | 952 | secretMaterial, |
| @@ -24,6 +24,7 @@ · 23 unmodified lines | ||
| 24 | 24 | "@effect/platform": "catalog:", |
| 25 | 25 | "@effect/platform-node": "catalog:", |
| 26 | 26 | "@effect/vitest": "catalog:", |
| 27 | + "@executor/effect-test-utils": "workspace:*", | |
| 27 | 28 | "@executor/platform-sdk-file": "workspace:*", |
| 28 | 29 | "@types/jsdom": "^21.1.7", |
| 29 | 30 | "@types/node": "catalog:", |
| @@ -1,8 +1,19 @@ | ||
| 1 | 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 | 12 | import { NodeFileSystem, NodeHttpServer } from "@effect/platform-node"; |
| 5 | 13 | import { describe, expect, it } from "@effect/vitest"; |
| 14 | +import { | |
| 15 | + startOpenApiTestServer, | |
| 16 | +} from "@executor/effect-test-utils"; | |
| 6 | 17 | import { |
| 7 | 18 | createExecutorApiLayer, |
| 8 | 19 | } from "@executor/platform-api"; |
| @@ -17,6 +28,7 @@ import * as Context from "effect/Context"; · 8 unmodified lines | ||
| 17 | 28 | import * as Effect from "effect/Effect"; |
| 18 | 29 | import * as Exit from "effect/Exit"; |
| 19 | 30 | import * as Layer from "effect/Layer"; |
| 31 | +import * as Schema from "effect/Schema"; | |
| 20 | 32 | import * as Scope from "effect/Scope"; |
| 21 | 33 | import { JSDOM } from "jsdom"; |
| 22 | 34 | import * as React from "react"; |
| @@ -225,83 +237,38 @@ type OpenApiSpecServer = RunningServer & { · 202 unmodified lines | ||
| 225 | 237 | specUrl: string; |
| 226 | 238 | }; |
| 227 | 239 | |
| 228 | −const startOpenApiSpecServer = async (): Promise<OpenApiSpecServer> => { | |
| 229 | − const spec = { | |
| 230 | − openapi: "3.0.3", | |
| 231 | − info: { | |
| 232 | − title: "Hook Test API", | |
| 233 | − version: "1.0.0", | |
| 234 | − }, | |
| 235 | − paths: { | |
| 236 | − "/ping": { | |
| 237 | − get: { | |
| 238 | − operationId: "ping", | |
| 239 | − responses: { | |
| 240 | − 200: { | |
| 241 | − description: "ok", | |
| 242 | − content: { | |
| 243 | − "application/json": { | |
| 244 | − schema: { | |
| 245 | − type: "object", | |
| 246 | − properties: { | |
| 247 | − ok: { type: "boolean" }, | |
| 248 | − }, | |
| 249 | − }, | |
| 250 | − }, | |
| 251 | − }, | |
| 252 | − }, | |
| 253 | − }, | |
| 254 | − }, | |
| 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 | − }); | |
| 240 | +class HooksTestPingApi extends HttpApiGroup.make("ping") | |
| 241 | + .add( | |
| 242 | + HttpApiEndpoint.get("ping")`/ping` | |
| 243 | + .addSuccess( | |
| 244 | + Schema.Struct({ | |
| 245 | + ok: Schema.Boolean, | |
| 246 | + }), | |
| 247 | + ), | |
| 248 | + ) | |
| 249 | +{} | |
| 250 | + | |
| 251 | +class HooksTestOpenApi extends HttpApi.make("hooksTest").add(HooksTestPingApi) {} | |
| 252 | + | |
| 253 | +const hooksTestOpenApiSpec = OpenApi.fromApi(HooksTestOpenApi); | |
| 254 | +const hooksTestOpenApiLive = HttpApiBuilder.group( | |
| 255 | + HooksTestOpenApi, | |
| 256 | + "ping", | |
| 257 | + (handlers) => | |
| 258 | + handlers.handle("ping", () => | |
| 259 | + Effect.succeed({ | |
| 260 | + ok: true, | |
| 261 | + }), | |
| 262 | + ), | |
| 263 | +); | |
| 264 | +const hooksTestOpenApiLayer = HttpApiBuilder.api(HooksTestOpenApi).pipe( | |
| 265 | + Layer.provide(hooksTestOpenApiLive), | |
| 266 | +); | |
| 277 | 267 | |
| 278 | − await new Promise<void>((resolve, reject) => { | |
| 279 | − server.once("error", reject); | |
| 280 | − server.listen(0, "127.0.0.1", () => resolve()); | |
| 268 | +const startOpenApiSpecServer = async (): Promise<OpenApiSpecServer> => { | |
| 269 | + return startOpenApiTestServer({ | |
| 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 | 274 | async function requestJson<T>(input: { |
| @@ -343,42 +310,14 @@ const seedStoredOpenApiSource = async (input: { · 35 unmodified lines | ||
| 343 | 310 | name: string; |
| 344 | 311 | specUrl?: string; |
| 345 | 312 | }): Promise<Source> => { |
| 346 | − const sourceDocumentText = JSON.stringify({ | |
| 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 | − }); | |
| 313 | + const sourceDocumentText = JSON.stringify(hooksTestOpenApiSpec); | |
| 375 | 314 | const specUrl = input.specUrl ?? `data:application/json,${encodeURIComponent(sourceDocumentText)}`; |
| 376 | 315 | |
| 377 | 316 | return requestJson<Source>({ |
| 378 | 317 | baseUrl: input.server.baseUrl, |
| 379 | − path: `/v1/workspaces/${input.installation.workspaceId}/sources`, | |
| 318 | + path: `/v1/workspaces/${input.installation.scopeId}/sources`, | |
| 380 | 319 | method: "POST", |
| 381 | − accountId: input.installation.accountId, | |
| 320 | + accountId: input.installation.actorScopeId, | |
| 382 | 321 | payload: { |
| 383 | 322 | name: input.name, |
| 384 | 323 | kind: "openapi", |
| @@ -32,7 +32,7 @@ import type { · 31 unmodified lines | ||
| 32 | 32 | SourceInspection, |
| 33 | 33 | SourceInspectionDiscoverResult, |
| 34 | 34 | SourceInspectionToolDetail, |
| 35 | − WorkspaceOauthClient, | |
| 35 | + ScopeOauthClient as WorkspaceOauthClient, | |
| 36 | 36 | } from "@executor/platform-sdk/schema"; |
| 37 | 37 | import * as Cause from "effect/Cause"; |
| 38 | 38 | import * as Effect from "effect/Effect"; |
| @@ -42,7 +42,7 @@ import * as Runtime from "effect/Runtime"; · 3 unmodified lines | ||
| 42 | 42 | import * as React from "react"; |
| 43 | 43 | |
| 44 | 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 | 46 | const PLACEHOLDER_ACCOUNT_ID = "acc_placeholder"; |
| 47 | 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 | 59 | type AtomKeyPart = string | number | boolean | null | undefined; |
| 60 | 60 | |
| 61 | −type SourcesKeyParts = readonly [boolean, Source["workspaceId"], string]; | |
| 62 | −type SourceKeyParts = readonly [boolean, Source["workspaceId"], string, Source["id"]]; | |
| 61 | +type SourcesKeyParts = readonly [boolean, Source["scopeId"], string]; | |
| 62 | +type SourceKeyParts = readonly [boolean, Source["scopeId"], string, Source["id"]]; | |
| 63 | 63 | type SourceToolDetailKeyParts = readonly [ |
| 64 | 64 | boolean, |
| 65 | − Source["workspaceId"], | |
| 65 | + Source["scopeId"], | |
| 66 | 66 | string, |
| 67 | 67 | Source["id"], |
| 68 | 68 | string | null, |
| 69 | 69 | ]; |
| 70 | 70 | type SourceDiscoveryKeyParts = readonly [ |
| 71 | 71 | boolean, |
| 72 | − Source["workspaceId"], | |
| 72 | + Source["scopeId"], | |
| 73 | 73 | string, |
| 74 | 74 | Source["id"], |
| 75 | 75 | string, |
| @@ -77,13 +77,13 @@ type SourceDiscoveryKeyParts = readonly [ · 1 unmodified line | ||
| 77 | 77 | ]; |
| 78 | 78 | type WorkspaceOauthClientsKeyParts = readonly [ |
| 79 | 79 | boolean, |
| 80 | − Source["workspaceId"], | |
| 80 | + Source["scopeId"], | |
| 81 | 81 | string, |
| 82 | 82 | string, |
| 83 | 83 | ]; |
| 84 | 84 | |
| 85 | 85 | type InvalidationTarget = { |
| 86 | − workspaceId?: Source["workspaceId"]; | |
| 86 | + workspaceId?: Source["scopeId"]; | |
| 87 | 87 | accountId?: string; |
| 88 | 88 | sourceId?: Source["id"]; |
| 89 | 89 | }; |
| @@ -104,7 +104,7 @@ type ExecutorQueryContextValue = { · 14 unmodified lines | ||
| 104 | 104 | }; |
| 105 | 105 | |
| 106 | 106 | type MutationExecutionContext = { |
| 107 | − workspaceId: Source["workspaceId"]; | |
| 107 | + workspaceId: Source["scopeId"]; | |
| 108 | 108 | accountId: string; |
| 109 | 109 | registry: Registry.Registry; |
| 110 | 110 | invalidateQueries: (target?: InvalidationTarget) => void; |
| @@ -149,20 +149,20 @@ const decodeAtomKey = <T extends ReadonlyArray<AtomKeyPart>>(key: string): T => · 38 unmodified lines | ||
| 149 | 149 | |
| 150 | 150 | const encodeSourcesKey = ( |
| 151 | 151 | enabled: boolean, |
| 152 | − workspaceId: Source["workspaceId"], | |
| 152 | + workspaceId: Source["scopeId"], | |
| 153 | 153 | accountId: string, |
| 154 | 154 | ): string => encodeAtomKey([enabled, workspaceId, accountId] satisfies SourcesKeyParts); |
| 155 | 155 | |
| 156 | 156 | const encodeSourceKey = ( |
| 157 | 157 | enabled: boolean, |
| 158 | − workspaceId: Source["workspaceId"], | |
| 158 | + workspaceId: Source["scopeId"], | |
| 159 | 159 | accountId: string, |
| 160 | 160 | sourceId: Source["id"], |
| 161 | 161 | ): string => encodeAtomKey([enabled, workspaceId, accountId, sourceId] satisfies SourceKeyParts); |
| 162 | 162 | |
| 163 | 163 | const encodeToolDetailKey = ( |
| 164 | 164 | enabled: boolean, |
| 165 | − workspaceId: Source["workspaceId"], | |
| 165 | + workspaceId: Source["scopeId"], | |
| 166 | 166 | accountId: string, |
| 167 | 167 | sourceId: Source["id"], |
| 168 | 168 | toolPath: string | null, |
| @@ -171,7 +171,7 @@ const encodeToolDetailKey = ( · 2 unmodified lines | ||
| 171 | 171 | |
| 172 | 172 | const encodeDiscoveryKey = ( |
| 173 | 173 | enabled: boolean, |
| 174 | − workspaceId: Source["workspaceId"], | |
| 174 | + workspaceId: Source["scopeId"], | |
| 175 | 175 | accountId: string, |
| 176 | 176 | sourceId: Source["id"], |
| 177 | 177 | query: string, |
| @@ -181,7 +181,7 @@ const encodeDiscoveryKey = ( · 3 unmodified lines | ||
| 181 | 181 | |
| 182 | 182 | const encodeWorkspaceOauthClientsKey = ( |
| 183 | 183 | enabled: boolean, |
| 184 | − workspaceId: Source["workspaceId"], | |
| 184 | + workspaceId: Source["scopeId"], | |
| 185 | 185 | accountId: string, |
| 186 | 186 | providerKey: string, |
| 187 | 187 | ): string => |
| @@ -430,7 +430,7 @@ export type Loadable<T> = · 242 unmodified lines | ||
| 430 | 430 | |
| 431 | 431 | type WorkspaceContext = { |
| 432 | 432 | installation: LocalInstallation; |
| 433 | − workspaceId: Source["workspaceId"]; | |
| 433 | + workspaceId: Source["scopeId"]; | |
| 434 | 434 | accountId: string; |
| 435 | 435 | }; |
| 436 | 436 | |
| @@ -483,8 +483,8 @@ const useWorkspaceContext = (): Loadable<WorkspaceContext> => { · 46 unmodified lines | ||
| 483 | 483 | status: "ready", |
| 484 | 484 | data: { |
| 485 | 485 | installation: installation.data, |
| 486 | − workspaceId: installation.data.workspaceId, | |
| 487 | − accountId: installation.data.accountId, | |
| 486 | + workspaceId: installation.data.scopeId, | |
| 487 | + accountId: installation.data.actorScopeId, | |
| 488 | 488 | }, |
| 489 | 489 | } satisfies Loadable<WorkspaceContext>; |
| 490 | 490 | }, [installation]); |
| @@ -559,7 +559,7 @@ const createActiveQueryCollections = (): ActiveQueryCollections => ({ · 68 unmodified lines | ||
| 559 | 559 | |
| 560 | 560 | const targetMatches = ( |
| 561 | 561 | target: InvalidationTarget | undefined, |
| 562 | − workspaceId: Source["workspaceId"], | |
| 562 | + workspaceId: Source["scopeId"], | |
| 563 | 563 | accountId: string, |
| 564 | 564 | sourceId?: Source["id"], |
| 565 | 565 | ): boolean => { |
| @@ -671,14 +671,14 @@ const removeSourceFromList = ( · 105 unmodified lines | ||
| 671 | 671 | ): ReadonlyArray<Source> => sources.filter((source) => source.id !== sourceId); |
| 672 | 672 | |
| 673 | 673 | const createOptimisticSource = (input: { |
| 674 | − workspaceId: Source["workspaceId"]; | |
| 674 | + workspaceId: Source["scopeId"]; | |
| 675 | 675 | payload: CreateSourcePayload; |
| 676 | 676 | }): Source => { |
| 677 | 677 | const now = Date.now(); |
| 678 | 678 | |
| 679 | 679 | return { |
| 680 | 680 | id: `src_optimistic_${crypto.randomUUID()}` as Source["id"], |
| 681 | − workspaceId: input.workspaceId, | |
| 681 | + scopeId: input.workspaceId, | |
| 682 | 682 | name: input.payload.name, |
| 683 | 683 | kind: input.payload.kind, |
| 684 | 684 | endpoint: input.payload.endpoint, |
| @@ -713,7 +713,7 @@ const applyUpdatePayloadToSource = (source: Source, payload: UpdateSourcePayload · 28 unmodified lines | ||
| 713 | 713 | |
| 714 | 714 | const useSourceMutation = <TInput, TOutput, TOptimistic = never>( |
| 715 | 715 | execute: (input: { |
| 716 | − workspaceId: Source["workspaceId"]; | |
| 716 | + workspaceId: Source["scopeId"]; | |
| 717 | 717 | accountId: string; |
| 718 | 718 | payload: TInput; |
| 719 | 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 | 154 | Effect.gen(function* () { |
| 155 | 155 | const resolveExecutionEnvironment = yield* RuntimeExecutionResolverService; |
| 156 | 156 | const environment = yield* resolveExecutionEnvironment({ |
| 157 | − workspaceId: runtime.localInstallation.workspaceId, | |
| 158 | − accountId: runtime.localInstallation.accountId, | |
| 157 | + scopeId: runtime.localInstallation.scopeId, | |
| 158 | + actorScopeId: runtime.localInstallation.actorScopeId, | |
| 159 | 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 | 261 | const waitForInteractionProgress = async (input: { |
| 262 | 262 | runtime: ExecutorRuntime; |
| 263 | − workspaceId: string; | |
| 263 | + scopeId: string; | |
| 264 | 264 | executionId: string; |
| 265 | 265 | pendingInteractionId: string; |
| 266 | 266 | }): Promise<ExecutionEnvelope> => { |
| @@ -268,7 +268,7 @@ const waitForInteractionProgress = async (input: { · 1 unmodified line | ||
| 268 | 268 | const next = await runControlPlane( |
| 269 | 269 | input.runtime, |
| 270 | 270 | getExecution({ |
| 271 | − workspaceId: input.workspaceId as never, | |
| 271 | + scopeId: input.scopeId as never, | |
| 272 | 272 | executionId: input.executionId as never, |
| 273 | 273 | }), |
| 274 | 274 | ); |
| @@ -286,8 +286,8 @@ const waitForInteractionProgress = async (input: { · 11 unmodified lines | ||
| 286 | 286 | |
| 287 | 287 | const driveExecutionWithElicitation = async (input: { |
| 288 | 288 | runtime: ExecutorRuntime; |
| 289 | − workspaceId: string; | |
| 290 | − accountId: string; | |
| 289 | + scopeId: string; | |
| 290 | + actorScopeId: string; | |
| 291 | 291 | server: McpServer; |
| 292 | 292 | envelope: ExecutionEnvelope; |
| 293 | 293 | }): Promise<ExecutionEnvelope> => { |
| @@ -317,13 +317,13 @@ const driveExecutionWithElicitation = async (input: { · 23 unmodified lines | ||
| 317 | 317 | current = await runControlPlane( |
| 318 | 318 | input.runtime, |
| 319 | 319 | resumeExecution({ |
| 320 | − workspaceId: input.workspaceId as never, | |
| 320 | + scopeId: input.scopeId as never, | |
| 321 | 321 | executionId: current.execution.id as never, |
| 322 | 322 | payload: { |
| 323 | 323 | responseJson: JSON.stringify(response), |
| 324 | 324 | interactionMode: interactionModeForServer(input.server), |
| 325 | 325 | }, |
| 326 | − resumedByAccountId: input.accountId as never, | |
| 326 | + resumedByScopeId: input.actorScopeId as never, | |
| 327 | 327 | }), |
| 328 | 328 | ); |
| 329 | 329 | continue; |
| @@ -340,13 +340,13 @@ const driveExecutionWithElicitation = async (input: { · 10 unmodified lines | ||
| 340 | 340 | current = await runControlPlane( |
| 341 | 341 | input.runtime, |
| 342 | 342 | resumeExecution({ |
| 343 | − workspaceId: input.workspaceId as never, | |
| 343 | + scopeId: input.scopeId as never, | |
| 344 | 344 | executionId: current.execution.id as never, |
| 345 | 345 | payload: { |
| 346 | 346 | responseJson: JSON.stringify(response), |
| 347 | 347 | interactionMode: interactionModeForServer(input.server), |
| 348 | 348 | }, |
| 349 | − resumedByAccountId: input.accountId as never, | |
| 349 | + resumedByScopeId: input.actorScopeId as never, | |
| 350 | 350 | }), |
| 351 | 351 | ); |
| 352 | 352 | continue; |
| @@ -354,7 +354,7 @@ const driveExecutionWithElicitation = async (input: { · 1 unmodified line | ||
| 354 | 354 | |
| 355 | 355 | current = await waitForInteractionProgress({ |
| 356 | 356 | runtime: input.runtime, |
| 357 | − workspaceId: input.workspaceId, | |
| 357 | + scopeId: input.scopeId, | |
| 358 | 358 | executionId: current.execution.id, |
| 359 | 359 | pendingInteractionId: pending.id, |
| 360 | 360 | }); |
| @@ -365,15 +365,15 @@ const driveExecutionWithElicitation = async (input: { · 4 unmodified lines | ||
| 365 | 365 | |
| 366 | 366 | const driveExecutionWithoutElicitation = async (input: { |
| 367 | 367 | runtime: ExecutorRuntime; |
| 368 | − workspaceId: string; | |
| 369 | − accountId: string; | |
| 368 | + scopeId: string; | |
| 369 | + actorScopeId: string; | |
| 370 | 370 | executionId: string; |
| 371 | 371 | initialResponse?: ResumeResponseInput; |
| 372 | 372 | }): Promise<ExecutionEnvelope> => { |
| 373 | 373 | let current = await runControlPlane( |
| 374 | 374 | input.runtime, |
| 375 | 375 | getExecution({ |
| 376 | − workspaceId: input.workspaceId as never, | |
| 376 | + scopeId: input.scopeId as never, | |
| 377 | 377 | executionId: input.executionId as never, |
| 378 | 378 | }), |
| 379 | 379 | ); |
| @@ -388,13 +388,13 @@ const driveExecutionWithoutElicitation = async (input: { · 8 unmodified lines | ||
| 388 | 388 | current = await runControlPlane( |
| 389 | 389 | input.runtime, |
| 390 | 390 | resumeExecution({ |
| 391 | − workspaceId: input.workspaceId as never, | |
| 391 | + scopeId: input.scopeId as never, | |
| 392 | 392 | executionId: current.execution.id as never, |
| 393 | 393 | payload: { |
| 394 | 394 | responseJson: JSON.stringify(response), |
| 395 | 395 | interactionMode: "detach", |
| 396 | 396 | }, |
| 397 | − resumedByAccountId: input.accountId as never, | |
| 397 | + resumedByScopeId: input.actorScopeId as never, | |
| 398 | 398 | }), |
| 399 | 399 | ); |
| 400 | 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; | |
| 420 | − const accountId = config.runtime.localInstallation.accountId; | |
| 419 | + const scopeId = config.runtime.localInstallation.scopeId; | |
| 420 | + const actorScopeId = config.runtime.localInstallation.actorScopeId; | |
| 421 | 421 | |
| 422 | 422 | const executeTool = server.registerTool( |
| 423 | 423 | "execute", |
| @@ -429,20 +429,20 @@ const createExecutorMcpServer = async (config: { · 5 unmodified lines | ||
| 429 | 429 | let created = await runControlPlane( |
| 430 | 430 | config.runtime, |
| 431 | 431 | createExecution({ |
| 432 | − workspaceId, | |
| 432 | + scopeId, | |
| 433 | 433 | payload: { |
| 434 | 434 | code, |
| 435 | 435 | interactionMode: interactionModeForServer(server), |
| 436 | 436 | }, |
| 437 | − createdByAccountId: accountId, | |
| 437 | + createdByScopeId: actorScopeId, | |
| 438 | 438 | }), |
| 439 | 439 | ); |
| 440 | 440 | |
| 441 | 441 | if (supportsManagedElicitation(server)) { |
| 442 | 442 | created = await driveExecutionWithElicitation({ |
| 443 | 443 | runtime: config.runtime, |
| 444 | − workspaceId, | |
| 445 | − accountId, | |
| 444 | + scopeId, | |
| 445 | + actorScopeId, | |
| 446 | 446 | server, |
| 447 | 447 | envelope: created, |
| 448 | 448 | }); |
| @@ -469,8 +469,8 @@ const createExecutorMcpServer = async (config: { · 20 unmodified lines | ||
| 469 | 469 | ) => { |
| 470 | 470 | const resumed = await driveExecutionWithoutElicitation({ |
| 471 | 471 | runtime: config.runtime, |
| 472 | − workspaceId, | |
| 473 | − accountId, | |
| 472 | + scopeId, | |
| 473 | + actorScopeId, | |
| 474 | 474 | executionId: input.resumePayload.executionId, |
| 475 | 475 | initialResponse: input.response, |
| 476 | 476 | }); |
| @@ -35,8 +35,8 @@ const makeEnvelope = ( · 34 unmodified lines | ||
| 35 | 35 | ): ExecutionEnvelope => ({ |
| 36 | 36 | execution: { |
| 37 | 37 | id: "exec_123" as never, |
| 38 | − workspaceId: "ws_123" as never, | |
| 39 | − createdByAccountId: "acct_123" as never, | |
| 38 | + scopeId: "ws_123" as never, | |
| 39 | + createdByScopeId: "acct_123" as never, | |
| 40 | 40 | status: "waiting_for_interaction", |
| 41 | 41 | code: "return await tools.executor.sources.add({ endpoint: 'https://mcp.axiom.co/mcp' });", |
| 42 | 42 | resultJson: null, |
| @@ -10,7 +10,7 @@ export type { · 9 unmodified lines | ||
| 10 | 10 | import { |
| 11 | 11 | ExecutionIdSchema, |
| 12 | 12 | ExecutionEnvelopeSchema, |
| 13 | − WorkspaceIdSchema, | |
| 13 | + ScopeIdSchema as WorkspaceIdSchema, | |
| 14 | 14 | } from "@executor/platform-sdk/schema"; |
| 15 | 15 | |
| 16 | 16 | import { |
| @@ -1,5 +1,5 @@ | ||
| 1 | 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 | 3 | import { |
| 4 | 4 | ControlPlaneBadRequestError, |
| 5 | 5 | ControlPlaneForbiddenError, |
| @@ -23,13 +23,13 @@ export const resolveRequestedLocalWorkspace = ( · 17 unmodified lines | ||
| 23 | 23 | workspaceId: WorkspaceId, |
| 24 | 24 | ) => |
| 25 | 25 | Effect.flatMap(ControlPlaneExecutor, (executor) => |
| 26 | − executor.workspaceId === workspaceId | |
| 26 | + executor.scopeId === workspaceId | |
| 27 | 27 | ? Effect.succeed(executor) |
| 28 | 28 | : Effect.fail( |
| 29 | 29 | new ControlPlaneForbiddenError({ |
| 30 | 30 | operation, |
| 31 | 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 | 4 | SourceAuthSessionIdSchema, |
| 5 | 5 | SourceTransportSchema, |
| 6 | 6 | StringMapSchema, |
| 7 | − WorkspaceIdSchema, | |
| 7 | + ScopeIdSchema as WorkspaceIdSchema, | |
| 8 | 8 | } from "@executor/platform-sdk/schema"; |
| 9 | 9 | import * as Schema from "effect/Schema"; |
| 10 | 10 | |
| @@ -3,7 +3,7 @@ import { · 2 unmodified lines | ||
| 3 | 3 | HttpServerRequest, |
| 4 | 4 | HttpServerResponse, |
| 5 | 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 | 7 | import * as Cause from "effect/Cause"; |
| 8 | 8 | import * as Either from "effect/Either"; |
| 9 | 9 | import * as Effect from "effect/Effect"; |
| @@ -11,9 +11,9 @@ import { · 10 unmodified lines | ||
| 11 | 11 | ControlPlaneUnauthorizedError, |
| 12 | 12 | } from "@executor/platform-sdk/errors"; |
| 13 | 13 | import { |
| 14 | − LocalWorkspacePolicySchema, | |
| 14 | + LocalScopePolicySchema as LocalWorkspacePolicySchema, | |
| 15 | 15 | PolicyIdSchema, |
| 16 | − WorkspaceIdSchema, | |
| 16 | + ScopeIdSchema as WorkspaceIdSchema, | |
| 17 | 17 | } from "@executor/platform-sdk/schema"; |
| 18 | 18 | import * as Schema from "effect/Schema"; |
| 19 | 19 | |
| @@ -5,13 +5,13 @@ import { · 4 unmodified lines | ||
| 5 | 5 | ConnectSourcePayloadSchema, |
| 6 | 6 | ConnectSourceResultSchema, |
| 7 | 7 | CreateSourcePayloadSchema, |
| 8 | − CreateWorkspaceOauthClientPayloadSchema, | |
| 8 | + CreateScopeOauthClientPayloadSchema as CreateWorkspaceOauthClientPayloadSchema, | |
| 9 | 9 | CredentialOauthCompleteUrlParamsSchema, |
| 10 | 10 | CredentialPageUrlParamsSchema, |
| 11 | 11 | CredentialSubmitPayloadSchema, |
| 12 | 12 | DiscoverSourcePayloadSchema, |
| 13 | 13 | UpdateSourcePayloadSchema, |
| 14 | − WorkspaceOauthClientQuerySchema, | |
| 14 | + ScopeOauthClientQuerySchema as WorkspaceOauthClientQuerySchema, | |
| 15 | 15 | } from "@executor/platform-sdk/contracts"; |
| 16 | 16 | import { |
| 17 | 17 | ControlPlaneBadRequestError, |
| @@ -29,9 +29,9 @@ import { · 11 unmodified lines | ||
| 29 | 29 | SourceInspectionSchema, |
| 30 | 30 | SourceInspectionToolDetailSchema, |
| 31 | 31 | SourceSchema, |
| 32 | − WorkspaceOauthClientIdSchema, | |
| 33 | − WorkspaceOauthClientSchema, | |
| 34 | − WorkspaceIdSchema, | |
| 32 | + ScopeOauthClientIdSchema as WorkspaceOauthClientIdSchema, | |
| 33 | + ScopeOauthClientSchema as WorkspaceOauthClientSchema, | |
| 34 | + ScopeIdSchema as WorkspaceIdSchema, | |
| 35 | 35 | } from "@executor/platform-sdk/schema"; |
| 36 | 36 | import * as Schema from "effect/Schema"; |
| 37 | 37 | |
| @@ -41,7 +41,7 @@ export type { · 3 unmodified lines | ||
| 41 | 41 | ConnectSourcePayload, |
| 42 | 42 | ConnectSourceResult, |
| 43 | 43 | CreateSourcePayload, |
| 44 | − CreateWorkspaceOauthClientPayload, | |
| 44 | + CreateScopeOauthClientPayload as CreateWorkspaceOauthClientPayload, | |
| 45 | 45 | DiscoverSourcePayload, |
| 46 | 46 | UpdateSourcePayload, |
| 47 | 47 | } from "@executor/platform-sdk/contracts"; |
| @@ -6,8 +6,8 @@ import { · 5 unmodified lines | ||
| 6 | 6 | import type { |
| 7 | 7 | ExecutionInteraction, |
| 8 | 8 | Source, |
| 9 | − WorkspaceId, | |
| 10 | − WorkspaceOauthClient, | |
| 9 | + ScopeId as WorkspaceId, | |
| 10 | + ScopeOauthClient as WorkspaceOauthClient, | |
| 11 | 11 | } from "@executor/platform-sdk/schema"; |
| 12 | 12 | import type { |
| 13 | 13 | ExecutorMcpSourceInput, |
| @@ -18,7 +18,7 @@ import * as Effect from "effect/Effect"; · 4 unmodified lines | ||
| 18 | 18 | import { |
| 19 | 19 | sourceAdapterRequiresInteractiveConnect, |
| 20 | 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 | 23 | import { |
| 24 | 24 | ControlPlaneBadRequestError, |
| @@ -130,8 +130,8 @@ const toExecutorSourceInput = ( · 105 unmodified lines | ||
| 130 | 130 | version: payload.version, |
| 131 | 131 | discoveryUrl: payload.discoveryUrl, |
| 132 | 132 | scopes: payload.scopes, |
| 133 | − workspaceOauthClientId: toWorkspaceOauthClientId( | |
| 134 | − payload.workspaceOauthClientId, | |
| 133 | + scopeOauthClientId: toWorkspaceOauthClientId( | |
| 134 | + payload.scopeOauthClientId, | |
| 135 | 135 | ), |
| 136 | 136 | oauthClient: payload.oauthClient, |
| 137 | 137 | name: payload.name, |
| @@ -1137,7 +1137,7 @@ export const ExecutorSourcesLive = HttpApiBuilder.group( · 999 unmodified lines | ||
| 1137 | 1137 | Effect.flatMap((executor) => |
| 1138 | 1138 | Effect.gen(function* () { |
| 1139 | 1139 | const completed = yield* executor.effect.oauth.completeProviderCallback({ |
| 1140 | − workspaceId: path.workspaceId, | |
| 1140 | + scopeId: path.workspaceId, | |
| 1141 | 1141 | state: urlParams.state, |
| 1142 | 1142 | code: urlParams.code, |
| 1143 | 1143 | error: urlParams.error, |
| @@ -1,9 +1,9 @@ | ||
| 1 | 1 | import { toTool, type ToolMap } from "@executor/codemode-core"; |
| 2 | 2 | import type { Executor } from "@executor/platform-sdk"; |
| 3 | 3 | import { |
| 4 | − type AccountId, | |
| 4 | + type ScopeId as AccountId, | |
| 5 | 5 | LocalInstallationSchema, |
| 6 | − LocalWorkspacePolicySchema, | |
| 6 | + LocalScopePolicySchema, | |
| 7 | 7 | SourceDiscoveryResultSchema, |
| 8 | 8 | SourceIdSchema, |
| 9 | 9 | SourceInspectionDiscoverPayloadSchema, |
| @@ -11,8 +11,8 @@ import { · 1 unmodified line | ||
| 11 | 11 | SourceInspectionSchema, |
| 12 | 12 | SourceInspectionToolDetailSchema, |
| 13 | 13 | SourceSchema, |
| 14 | − type WorkspaceId, | |
| 15 | − WorkspaceOauthClientSchema, | |
| 14 | + type ScopeId as WorkspaceId, | |
| 15 | + ScopeOauthClientSchema, | |
| 16 | 16 | } from "@executor/platform-sdk/schema"; |
| 17 | 17 | import * as Effect from "effect/Effect"; |
| 18 | 18 | import * as Layer from "effect/Layer"; |
| @@ -25,25 +25,25 @@ import { · 6 unmodified lines | ||
| 25 | 25 | SecretMaterialStorerService, |
| 26 | 26 | SecretMaterialUpdaterService, |
| 27 | 27 | type ExecutorStateStoreShape, |
| 28 | − type WorkspaceInternalToolContext, | |
| 28 | + type ScopeInternalToolContext as WorkspaceInternalToolContext, | |
| 29 | 29 | RuntimeSourceAuthService, |
| 30 | 30 | RuntimeSourceCatalogSyncService, |
| 31 | 31 | RuntimeSourceStore, |
| 32 | 32 | RuntimeSourceStoreService, |
| 33 | 33 | } from "@executor/platform-sdk/runtime"; |
| 34 | 34 | import { |
| 35 | − type RuntimeLocalWorkspaceState, | |
| 36 | − provideOptionalRuntimeLocalWorkspace, | |
| 37 | −} from "../../../sdk/src/runtime/workspace/runtime-context"; | |
| 35 | + type RuntimeLocalScopeState, | |
| 36 | + provideOptionalRuntimeLocalScope, | |
| 37 | +} from "../../../sdk/src/runtime/scope/runtime-context"; | |
| 38 | 38 | import { |
| 39 | 39 | SourceArtifactStore, |
| 40 | 40 | type SourceArtifactStoreShape, |
| 41 | − WorkspaceConfigStore, | |
| 42 | − type WorkspaceConfigStoreShape, | |
| 43 | − WorkspaceStateStore, | |
| 44 | − type WorkspaceStateStoreShape, | |
| 45 | − makeWorkspaceStorageLayer, | |
| 46 | −} from "../../../sdk/src/runtime/workspace/storage"; | |
| 41 | + ScopeConfigStore, | |
| 42 | + type ScopeConfigStoreShape, | |
| 43 | + ScopeStateStore, | |
| 44 | + type ScopeStateStoreShape, | |
| 45 | + makeScopeStorageLayer, | |
| 46 | +} from "../../../sdk/src/runtime/scope/storage"; | |
| 47 | 47 | import { |
| 48 | 48 | CreateSecretPayloadSchema, |
| 49 | 49 | CreateSecretResultSchema, |
| @@ -81,9 +81,9 @@ import { · 31 unmodified lines | ||
| 81 | 81 | UpdatePolicyPayloadSchema, |
| 82 | 82 | } from "@executor/platform-sdk/contracts"; |
| 83 | 83 | import { |
| 84 | − CreateWorkspaceOauthClientPayloadSchema, | |
| 84 | + CreateScopeOauthClientPayloadSchema, | |
| 85 | 85 | DiscoverSourcePayloadSchema, |
| 86 | − type CreateWorkspaceOauthClientPayload, | |
| 86 | + type CreateScopeOauthClientPayload as CreateWorkspaceOauthClientPayload, | |
| 87 | 87 | UpdateSourcePayloadSchema, |
| 88 | 88 | } from "@executor/platform-sdk/contracts"; |
| 89 | 89 | |
| @@ -145,7 +145,7 @@ const inspectDiscoverInputSchema = Schema.standardSchemaV1( · 55 unmodified lines | ||
| 145 | 145 | }), |
| 146 | 146 | ); |
| 147 | 147 | const listPoliciesOutputSchema = Schema.standardSchemaV1( |
| 148 | − Schema.Array(LocalWorkspacePolicySchema), | |
| 148 | + Schema.Array(LocalScopePolicySchema), | |
| 149 | 149 | ); |
| 150 | 150 | const policyIdInputSchema = Schema.standardSchemaV1( |
| 151 | 151 | Schema.Struct({ |
| @@ -167,10 +167,10 @@ const workspaceOauthClientListInputSchema = Schema.standardSchemaV1( · 15 unmodified lines | ||
| 167 | 167 | }), |
| 168 | 168 | ); |
| 169 | 169 | const workspaceOauthClientListOutputSchema = Schema.standardSchemaV1( |
| 170 | − Schema.Array(WorkspaceOauthClientSchema), | |
| 170 | + Schema.Array(ScopeOauthClientSchema), | |
| 171 | 171 | ); |
| 172 | 172 | const createWorkspaceOauthClientInputSchema = Schema.standardSchemaV1( |
| 173 | − CreateWorkspaceOauthClientPayloadSchema, | |
| 173 | + CreateScopeOauthClientPayloadSchema, | |
| 174 | 174 | ); |
| 175 | 175 | const removeWorkspaceOauthClientInputSchema = Schema.standardSchemaV1( |
| 176 | 176 | Schema.Struct({ |
| @@ -195,8 +195,8 @@ const sourceInspectionDiscoverOutputSchema = Schema.standardSchemaV1( · 18 unmodified lines | ||
| 195 | 195 | const sourceDiscoveryOutputSchema = Schema.standardSchemaV1( |
| 196 | 196 | SourceDiscoveryResultSchema, |
| 197 | 197 | ); |
| 198 | −const localWorkspacePolicyOutputSchema = Schema.standardSchemaV1( | |
| 199 | − LocalWorkspacePolicySchema, | |
| 198 | +const localScopePolicyOutputSchema = Schema.standardSchemaV1( | |
| 199 | + LocalScopePolicySchema, | |
| 200 | 200 | ); |
| 201 | 201 | |
| 202 | 202 | const makeRuntimeLayer = (input: { |
| @@ -205,8 +205,8 @@ const makeRuntimeLayer = (input: { · 2 unmodified lines | ||
| 205 | 205 | sourceCatalogSyncService: Effect.Effect.Success< |
| 206 | 206 | typeof RuntimeSourceCatalogSyncService |
| 207 | 207 | >; |
| 208 | − workspaceConfigStore: WorkspaceConfigStoreShape; | |
| 209 | − workspaceStateStore: WorkspaceStateStoreShape; | |
| 208 | + scopeConfigStore: ScopeConfigStoreShape; | |
| 209 | + scopeStateStore: ScopeStateStoreShape; | |
| 210 | 210 | sourceArtifactStore: SourceArtifactStoreShape; |
| 211 | 211 | instanceConfigResolver: WorkspaceInternalToolContext["instanceConfigResolver"]; |
| 212 | 212 | storeSecretMaterial: WorkspaceInternalToolContext["storeSecretMaterial"]; |
| @@ -224,9 +224,9 @@ const makeRuntimeLayer = (input: { · 11 unmodified lines | ||
| 224 | 224 | Layer.succeed(SecretMaterialStorerService, input.storeSecretMaterial), |
| 225 | 225 | Layer.succeed(SecretMaterialDeleterService, input.deleteSecretMaterial), |
| 226 | 226 | Layer.succeed(SecretMaterialUpdaterService, input.updateSecretMaterial), |
| 227 | − makeWorkspaceStorageLayer({ | |
| 228 | − workspaceConfigStore: input.workspaceConfigStore, | |
| 229 | − workspaceStateStore: input.workspaceStateStore, | |
| 227 | + makeScopeStorageLayer({ | |
| 228 | + scopeConfigStore: input.scopeConfigStore, | |
| 229 | + scopeStateStore: input.scopeStateStore, | |
| 230 | 230 | sourceArtifactStore: input.sourceArtifactStore, |
| 231 | 231 | }), |
| 232 | 232 | ); |
| @@ -241,34 +241,34 @@ const runRuntimeEffect = <A, E, R>(input: { · 8 unmodified lines | ||
| 241 | 241 | | SecretMaterialStorerService |
| 242 | 242 | | SecretMaterialDeleterService |
| 243 | 243 | | SecretMaterialUpdaterService |
| 244 | − | WorkspaceConfigStore | |
| 245 | − | WorkspaceStateStore | |
| 244 | + | ScopeConfigStore | |
| 245 | + | ScopeStateStore | |
| 246 | 246 | | SourceArtifactStore, |
| 247 | 247 | never, |
| 248 | 248 | never |
| 249 | 249 | >; |
| 250 | − runtimeLocalWorkspace: RuntimeLocalWorkspaceState | null; | |
| 250 | + runtimeLocalScope: RuntimeLocalScopeState | null; | |
| 251 | 251 | }) => |
| 252 | 252 | Effect.runPromise( |
| 253 | − provideOptionalRuntimeLocalWorkspace( | |
| 253 | + provideOptionalRuntimeLocalScope( | |
| 254 | 254 | input.effect.pipe(Effect.provide(input.runtimeLayer)), |
| 255 | − input.runtimeLocalWorkspace, | |
| 255 | + input.runtimeLocalScope, | |
| 256 | 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 | 260 | effect: Effect.Effect<A, E, R>; |
| 261 | − workspaceStorageLayer: Layer.Layer< | |
| 262 | − WorkspaceConfigStore | WorkspaceStateStore | SourceArtifactStore, | |
| 261 | + scopeStorageLayer: Layer.Layer< | |
| 262 | + ScopeConfigStore | ScopeStateStore | SourceArtifactStore, | |
| 263 | 263 | never, |
| 264 | 264 | never |
| 265 | 265 | >; |
| 266 | − runtimeLocalWorkspace: RuntimeLocalWorkspaceState | null; | |
| 266 | + runtimeLocalScope: RuntimeLocalScopeState | null; | |
| 267 | 267 | }) => |
| 268 | 268 | Effect.runPromise( |
| 269 | − provideOptionalRuntimeLocalWorkspace( | |
| 270 | − input.effect.pipe(Effect.provide(input.workspaceStorageLayer)), | |
| 271 | − input.runtimeLocalWorkspace, | |
| 269 | + provideOptionalRuntimeLocalScope( | |
| 270 | + input.effect.pipe(Effect.provide(input.scopeStorageLayer)), | |
| 271 | + input.runtimeLocalScope, | |
| 272 | 272 | ) as Effect.Effect<A, E, never>, |
| 273 | 273 | ); |
| 274 | 274 | |
| @@ -279,17 +279,17 @@ export const createWorkspaceExecutorAdminToolMap = ( · 4 unmodified lines | ||
| 279 | 279 | executorStateStore: input.executorStateStore, |
| 280 | 280 | sourceStore: input.sourceStore, |
| 281 | 281 | sourceCatalogSyncService: input.sourceCatalogSyncService, |
| 282 | − workspaceConfigStore: input.workspaceConfigStore, | |
| 283 | − workspaceStateStore: input.workspaceStateStore, | |
| 282 | + scopeConfigStore: input.scopeConfigStore, | |
| 283 | + scopeStateStore: input.scopeStateStore, | |
| 284 | 284 | sourceArtifactStore: input.sourceArtifactStore, |
| 285 | 285 | instanceConfigResolver: input.instanceConfigResolver, |
| 286 | 286 | storeSecretMaterial: input.storeSecretMaterial, |
| 287 | 287 | deleteSecretMaterial: input.deleteSecretMaterial, |
| 288 | 288 | updateSecretMaterial: input.updateSecretMaterial, |
| 289 | 289 | }); |
| 290 | − const workspaceStorageLayer = makeWorkspaceStorageLayer({ | |
| 291 | − workspaceConfigStore: input.workspaceConfigStore, | |
| 292 | − workspaceStateStore: input.workspaceStateStore, | |
| 290 | + const scopeStorageLayer = makeScopeStorageLayer({ | |
| 291 | + scopeConfigStore: input.scopeConfigStore, | |
| 292 | + scopeStateStore: input.scopeStateStore, | |
| 293 | 293 | sourceArtifactStore: input.sourceArtifactStore, |
| 294 | 294 | }); |
| 295 | 295 | |
| @@ -306,8 +306,8 @@ export const createWorkspaceExecutorAdminToolMap = ( · 10 unmodified lines | ||
| 306 | 306 | inputSchema: emptyInputSchema, |
| 307 | 307 | outputSchema: localInstallationOutputSchema, |
| 308 | 308 | execute: async () => ({ |
| 309 | − workspaceId: input.workspaceId, | |
| 310 | − accountId: input.accountId, | |
| 309 | + scopeId: input.scopeId, | |
| 310 | + actorScopeId: input.actorScopeId, | |
| 311 | 311 | }), |
| 312 | 312 | }, |
| 313 | 313 | metadata, |
| @@ -332,7 +332,7 @@ export const createWorkspaceExecutorAdminToolMap = ( · 18 unmodified lines | ||
| 332 | 332 | runRuntimeEffect({ |
| 333 | 333 | effect: listLocalSecrets(), |
| 334 | 334 | runtimeLayer, |
| 335 | − runtimeLocalWorkspace: input.runtimeLocalWorkspace, | |
| 335 | + runtimeLocalScope: input.runtimeLocalScope, | |
| 336 | 336 | }), |
| 337 | 337 | }, |
| 338 | 338 | metadata, |
| @@ -347,7 +347,7 @@ export const createWorkspaceExecutorAdminToolMap = ( · 8 unmodified lines | ||
| 347 | 347 | runRuntimeEffect({ |
| 348 | 348 | effect: createLocalSecret(payload), |
| 349 | 349 | runtimeLayer, |
| 350 | − runtimeLocalWorkspace: input.runtimeLocalWorkspace, | |
| 350 | + runtimeLocalScope: input.runtimeLocalScope, | |
| 351 | 351 | }), |
| 352 | 352 | }, |
| 353 | 353 | metadata, |
| @@ -365,7 +365,7 @@ export const createWorkspaceExecutorAdminToolMap = ( · 11 unmodified lines | ||
| 365 | 365 | runRuntimeEffect({ |
| 366 | 366 | effect: updateLocalSecret(payload), |
| 367 | 367 | runtimeLayer, |
| 368 | − runtimeLocalWorkspace: input.runtimeLocalWorkspace, | |
| 368 | + runtimeLocalScope: input.runtimeLocalScope, | |
| 369 | 369 | }), |
| 370 | 370 | }, |
| 371 | 371 | metadata, |
| @@ -379,7 +379,7 @@ export const createWorkspaceExecutorAdminToolMap = ( · 7 unmodified lines | ||
| 379 | 379 | runRuntimeEffect({ |
| 380 | 380 | effect: deleteLocalSecret(secretId), |
| 381 | 381 | runtimeLayer, |
| 382 | − runtimeLocalWorkspace: input.runtimeLocalWorkspace, | |
| 382 | + runtimeLocalScope: input.runtimeLocalScope, | |
| 383 | 383 | }), |
| 384 | 384 | }, |
| 385 | 385 | metadata, |
| @@ -408,11 +408,11 @@ export const createWorkspaceExecutorAdminToolMap = ( · 22 unmodified lines | ||
| 408 | 408 | execute: () => |
| 409 | 409 | runRuntimeEffect({ |
| 410 | 410 | effect: listSources({ |
| 411 | − workspaceId: input.workspaceId, | |
| 412 | − accountId: input.accountId as never, | |
| 411 | + scopeId: input.scopeId, | |
| 412 | + actorScopeId: input.actorScopeId as never, | |
| 413 | 413 | }), |
| 414 | 414 | runtimeLayer, |
| 415 | − runtimeLocalWorkspace: input.runtimeLocalWorkspace, | |
| 415 | + runtimeLocalScope: input.runtimeLocalScope, | |
| 416 | 416 | }), |
| 417 | 417 | }, |
| 418 | 418 | metadata, |
| @@ -425,12 +425,12 @@ export const createWorkspaceExecutorAdminToolMap = ( · 6 unmodified lines | ||
| 425 | 425 | execute: ({ sourceId }: { sourceId: string }) => |
| 426 | 426 | runRuntimeEffect({ |
| 427 | 427 | effect: getSource({ |
| 428 | − workspaceId: input.workspaceId, | |
| 428 | + scopeId: input.scopeId, | |
| 429 | 429 | sourceId: sourceId as never, |
| 430 | − accountId: input.accountId as never, | |
| 430 | + actorScopeId: input.actorScopeId as never, | |
| 431 | 431 | }), |
| 432 | 432 | runtimeLayer, |
| 433 | − runtimeLocalWorkspace: input.runtimeLocalWorkspace, | |
| 433 | + runtimeLocalScope: input.runtimeLocalScope, | |
| 434 | 434 | }), |
| 435 | 435 | }, |
| 436 | 436 | metadata, |
| @@ -446,13 +446,13 @@ export const createWorkspaceExecutorAdminToolMap = ( · 9 unmodified lines | ||
| 446 | 446 | }) => |
| 447 | 447 | runRuntimeEffect({ |
| 448 | 448 | effect: updateSource({ |
| 449 | − workspaceId: input.workspaceId, | |
| 449 | + scopeId: input.scopeId, | |
| 450 | 450 | sourceId: payload.sourceId as never, |
| 451 | − accountId: input.accountId as never, | |
| 451 | + actorScopeId: input.actorScopeId as never, | |
| 452 | 452 | payload: payload.payload as never, |
| 453 | 453 | }), |
| 454 | 454 | runtimeLayer, |
| 455 | − runtimeLocalWorkspace: input.runtimeLocalWorkspace, | |
| 455 | + runtimeLocalScope: input.runtimeLocalScope, | |
| 456 | 456 | }), |
| 457 | 457 | }, |
| 458 | 458 | metadata, |
| @@ -465,11 +465,11 @@ export const createWorkspaceExecutorAdminToolMap = ( · 6 unmodified lines | ||
| 465 | 465 | execute: ({ sourceId }: { sourceId: string }) => |
| 466 | 466 | runRuntimeEffect({ |
| 467 | 467 | effect: removeSource({ |
| 468 | − workspaceId: input.workspaceId, | |
| 468 | + scopeId: input.scopeId, | |
| 469 | 469 | sourceId: sourceId as never, |
| 470 | 470 | }), |
| 471 | 471 | runtimeLayer, |
| 472 | − runtimeLocalWorkspace: input.runtimeLocalWorkspace, | |
| 472 | + runtimeLocalScope: input.runtimeLocalScope, | |
| 473 | 473 | }), |
| 474 | 474 | }, |
| 475 | 475 | metadata, |
| @@ -482,11 +482,11 @@ export const createWorkspaceExecutorAdminToolMap = ( · 6 unmodified lines | ||
| 482 | 482 | execute: ({ sourceId }: { sourceId: string }) => |
| 483 | 483 | runRuntimeEffect({ |
| 484 | 484 | effect: getSourceInspection({ |
| 485 | − workspaceId: input.workspaceId, | |
| 485 | + scopeId: input.scopeId, | |
| 486 | 486 | sourceId: sourceId as never, |
| 487 | 487 | }), |
| 488 | 488 | runtimeLayer, |
| 489 | − runtimeLocalWorkspace: input.runtimeLocalWorkspace, | |
| 489 | + runtimeLocalScope: input.runtimeLocalScope, | |
| 490 | 490 | }), |
| 491 | 491 | }, |
| 492 | 492 | metadata, |
| @@ -505,12 +505,12 @@ export const createWorkspaceExecutorAdminToolMap = ( · 12 unmodified lines | ||
| 505 | 505 | }) => |
| 506 | 506 | runRuntimeEffect({ |
| 507 | 507 | effect: getSourceInspectionToolDetail({ |
| 508 | − workspaceId: input.workspaceId, | |
| 508 | + scopeId: input.scopeId, | |
| 509 | 509 | sourceId: sourceId as never, |
| 510 | 510 | toolPath, |
| 511 | 511 | }), |
| 512 | 512 | runtimeLayer, |
| 513 | − runtimeLocalWorkspace: input.runtimeLocalWorkspace, | |
| 513 | + runtimeLocalScope: input.runtimeLocalScope, | |
| 514 | 514 | }), |
| 515 | 515 | }, |
| 516 | 516 | metadata, |
| @@ -529,12 +529,12 @@ export const createWorkspaceExecutorAdminToolMap = ( · 12 unmodified lines | ||
| 529 | 529 | }) => |
| 530 | 530 | runRuntimeEffect({ |
| 531 | 531 | effect: discoverSourceInspectionTools({ |
| 532 | − workspaceId: input.workspaceId, | |
| 532 | + scopeId: input.scopeId, | |
| 533 | 533 | sourceId: sourceId as never, |
| 534 | 534 | payload: payload as never, |
| 535 | 535 | }), |
| 536 | 536 | runtimeLayer, |
| 537 | − runtimeLocalWorkspace: input.runtimeLocalWorkspace, | |
| 537 | + runtimeLocalScope: input.runtimeLocalScope, | |
| 538 | 538 | }), |
| 539 | 539 | }, |
| 540 | 540 | metadata, |
| @@ -545,13 +545,13 @@ export const createWorkspaceExecutorAdminToolMap = ( · 4 unmodified lines | ||
| 545 | 545 | inputSchema: workspaceOauthClientListInputSchema, |
| 546 | 546 | outputSchema: workspaceOauthClientListOutputSchema, |
| 547 | 547 | execute: ({ providerKey }: { providerKey: string }) => |
| 548 | − runWorkspaceStorageEffect({ | |
| 549 | − effect: input.sourceAuthService.listWorkspaceOauthClients({ | |
| 550 | − workspaceId: input.workspaceId, | |
| 548 | + runScopeStorageEffect({ | |
| 549 | + effect: input.sourceAuthService.listScopeOauthClients({ | |
| 550 | + scopeId: input.scopeId, | |
| 551 | 551 | providerKey, |
| 552 | 552 | }), |
| 553 | − workspaceStorageLayer, | |
| 554 | − runtimeLocalWorkspace: input.runtimeLocalWorkspace, | |
| 553 | + scopeStorageLayer, | |
| 554 | + runtimeLocalScope: input.runtimeLocalScope, | |
| 555 | 555 | }), |
| 556 | 556 | }, |
| 557 | 557 | metadata, |
| @@ -561,17 +561,17 @@ export const createWorkspaceExecutorAdminToolMap = ( · 3 unmodified lines | ||
| 561 | 561 | description: |
| 562 | 562 | "Create a workspace OAuth client used for shared provider auth flows.", |
| 563 | 563 | inputSchema: createWorkspaceOauthClientInputSchema, |
| 564 | − outputSchema: Schema.standardSchemaV1(WorkspaceOauthClientSchema), | |
| 564 | + outputSchema: Schema.standardSchemaV1(ScopeOauthClientSchema), | |
| 565 | 565 | execute: (payload: CreateWorkspaceOauthClientPayload) => |
| 566 | − runWorkspaceStorageEffect({ | |
| 567 | − effect: input.sourceAuthService.createWorkspaceOauthClient({ | |
| 568 | − workspaceId: input.workspaceId, | |
| 566 | + runScopeStorageEffect({ | |
| 567 | + effect: input.sourceAuthService.createScopeOauthClient({ | |
| 568 | + scopeId: input.scopeId, | |
| 569 | 569 | providerKey: payload.providerKey, |
| 570 | 570 | label: payload.label, |
| 571 | 571 | oauthClient: payload.oauthClient, |
| 572 | 572 | }), |
| 573 | − workspaceStorageLayer, | |
| 574 | − runtimeLocalWorkspace: input.runtimeLocalWorkspace, | |
| 573 | + scopeStorageLayer, | |
| 574 | + runtimeLocalScope: input.runtimeLocalScope, | |
| 575 | 575 | }), |
| 576 | 576 | }, |
| 577 | 577 | metadata, |
| @@ -582,15 +582,15 @@ export const createWorkspaceExecutorAdminToolMap = ( · 4 unmodified lines | ||
| 582 | 582 | inputSchema: removeWorkspaceOauthClientInputSchema, |
| 583 | 583 | outputSchema: removeResultSchema, |
| 584 | 584 | execute: ({ oauthClientId }: { oauthClientId: string }) => |
| 585 | − runWorkspaceStorageEffect({ | |
| 585 | + runScopeStorageEffect({ | |
| 586 | 586 | effect: input.sourceAuthService |
| 587 | − .removeWorkspaceOauthClient({ | |
| 588 | − workspaceId: input.workspaceId, | |
| 587 | + .removeScopeOauthClient({ | |
| 588 | + scopeId: input.scopeId, | |
| 589 | 589 | oauthClientId: oauthClientId as never, |
| 590 | 590 | }) |
| 591 | 591 | .pipe(Effect.map((removed) => ({ removed }))), |
| 592 | − workspaceStorageLayer, | |
| 593 | − runtimeLocalWorkspace: input.runtimeLocalWorkspace, | |
| 592 | + scopeStorageLayer, | |
| 593 | + runtimeLocalScope: input.runtimeLocalScope, | |
| 594 | 594 | }), |
| 595 | 595 | }, |
| 596 | 596 | metadata, |
| @@ -602,15 +602,15 @@ export const createWorkspaceExecutorAdminToolMap = ( · 5 unmodified lines | ||
| 602 | 602 | inputSchema: removeProviderGrantInputSchema, |
| 603 | 603 | outputSchema: removeResultSchema, |
| 604 | 604 | execute: ({ grantId }: { grantId: string }) => |
| 605 | − runWorkspaceStorageEffect({ | |
| 605 | + runScopeStorageEffect({ | |
| 606 | 606 | effect: input.sourceAuthService |
| 607 | 607 | .removeProviderAuthGrant({ |
| 608 | − workspaceId: input.workspaceId, | |
| 608 | + scopeId: input.scopeId, | |
| 609 | 609 | grantId: grantId as never, |
| 610 | 610 | }) |
| 611 | 611 | .pipe(Effect.map((removed) => ({ removed }))), |
| 612 | − workspaceStorageLayer, | |
| 613 | − runtimeLocalWorkspace: input.runtimeLocalWorkspace, | |
| 612 | + scopeStorageLayer, | |
| 613 | + runtimeLocalScope: input.runtimeLocalScope, | |
| 614 | 614 | }), |
| 615 | 615 | }, |
| 616 | 616 | metadata, |
| @@ -622,9 +622,9 @@ export const createWorkspaceExecutorAdminToolMap = ( · 5 unmodified lines | ||
| 622 | 622 | outputSchema: listPoliciesOutputSchema, |
| 623 | 623 | execute: () => |
| 624 | 624 | runRuntimeEffect({ |
| 625 | − effect: listPolicies(input.workspaceId), | |
| 625 | + effect: listPolicies(input.scopeId), | |
| 626 | 626 | runtimeLayer, |
| 627 | − runtimeLocalWorkspace: input.runtimeLocalWorkspace, | |
| 627 | + runtimeLocalScope: input.runtimeLocalScope, | |
| 628 | 628 | }), |
| 629 | 629 | }, |
| 630 | 630 | metadata, |
| @@ -633,15 +633,15 @@ export const createWorkspaceExecutorAdminToolMap = ( · 2 unmodified lines | ||
| 633 | 633 | tool: { |
| 634 | 634 | description: "Create a local workspace policy.", |
| 635 | 635 | inputSchema: createPolicyInputSchema, |
| 636 | − outputSchema: localWorkspacePolicyOutputSchema, | |
| 636 | + outputSchema: localScopePolicyOutputSchema, | |
| 637 | 637 | execute: (payload: CreatePolicyPayload) => |
| 638 | 638 | runRuntimeEffect({ |
| 639 | 639 | effect: createPolicy({ |
| 640 | − workspaceId: input.workspaceId, | |
| 640 | + scopeId: input.scopeId, | |
| 641 | 641 | payload, |
| 642 | 642 | }), |
| 643 | 643 | runtimeLayer, |
| 644 | − runtimeLocalWorkspace: input.runtimeLocalWorkspace, | |
| 644 | + runtimeLocalScope: input.runtimeLocalScope, | |
| 645 | 645 | }), |
| 646 | 646 | }, |
| 647 | 647 | metadata, |
| @@ -650,15 +650,15 @@ export const createWorkspaceExecutorAdminToolMap = ( · 2 unmodified lines | ||
| 650 | 650 | tool: { |
| 651 | 651 | description: "Get one local workspace policy by id.", |
| 652 | 652 | inputSchema: policyIdInputSchema, |
| 653 | − outputSchema: localWorkspacePolicyOutputSchema, | |
| 653 | + outputSchema: localScopePolicyOutputSchema, | |
| 654 | 654 | execute: ({ policyId }: { policyId: string }) => |
| 655 | 655 | runRuntimeEffect({ |
| 656 | 656 | effect: getPolicy({ |
| 657 | − workspaceId: input.workspaceId, | |
| 657 | + scopeId: input.scopeId, | |
| 658 | 658 | policyId: policyId as never, |
| 659 | 659 | }), |
| 660 | 660 | runtimeLayer, |
| 661 | − runtimeLocalWorkspace: input.runtimeLocalWorkspace, | |
| 661 | + runtimeLocalScope: input.runtimeLocalScope, | |
| 662 | 662 | }), |
| 663 | 663 | }, |
| 664 | 664 | metadata, |
| @@ -667,7 +667,7 @@ export const createWorkspaceExecutorAdminToolMap = ( · 2 unmodified lines | ||
| 667 | 667 | tool: { |
| 668 | 668 | description: "Update a local workspace policy.", |
| 669 | 669 | inputSchema: updatePolicyInputSchema, |
| 670 | − outputSchema: localWorkspacePolicyOutputSchema, | |
| 670 | + outputSchema: localScopePolicyOutputSchema, | |
| 671 | 671 | execute: ({ |
| 672 | 672 | policyId, |
| 673 | 673 | payload, |
| @@ -677,12 +677,12 @@ export const createWorkspaceExecutorAdminToolMap = ( · 3 unmodified lines | ||
| 677 | 677 | }) => |
| 678 | 678 | runRuntimeEffect({ |
| 679 | 679 | effect: updatePolicy({ |
| 680 | − workspaceId: input.workspaceId, | |
| 680 | + scopeId: input.scopeId, | |
| 681 | 681 | policyId: policyId as never, |
| 682 | 682 | payload, |
| 683 | 683 | }), |
| 684 | 684 | runtimeLayer, |
| 685 | − runtimeLocalWorkspace: input.runtimeLocalWorkspace, | |
| 685 | + runtimeLocalScope: input.runtimeLocalScope, | |
| 686 | 686 | }), |
| 687 | 687 | }, |
| 688 | 688 | metadata, |
| @@ -695,11 +695,11 @@ export const createWorkspaceExecutorAdminToolMap = ( · 6 unmodified lines | ||
| 695 | 695 | execute: ({ policyId }: { policyId: string }) => |
| 696 | 696 | runRuntimeEffect({ |
| 697 | 697 | effect: removePolicy({ |
| 698 | − workspaceId: input.workspaceId, | |
| 698 | + scopeId: input.scopeId, | |
| 699 | 699 | policyId: policyId as never, |
| 700 | 700 | }), |
| 701 | 701 | runtimeLayer, |
| 702 | − runtimeLocalWorkspace: input.runtimeLocalWorkspace, | |
| 702 | + runtimeLocalScope: input.runtimeLocalScope, | |
| 703 | 703 | }), |
| 704 | 704 | }, |
| 705 | 705 | metadata, |
| @@ -903,7 +903,7 @@ export const createExecutorAdminToolMap = (input: { · 197 unmodified lines | ||
| 903 | 903 | description: |
| 904 | 904 | "Create a workspace OAuth client for a provider-backed source flow.", |
| 905 | 905 | inputSchema: createWorkspaceOauthClientInputSchema, |
| 906 | − outputSchema: Schema.standardSchemaV1(WorkspaceOauthClientSchema), | |
| 906 | + outputSchema: Schema.standardSchemaV1(ScopeOauthClientSchema), | |
| 907 | 907 | execute: (payload: CreateWorkspaceOauthClientPayload) => |
| 908 | 908 | input.executor.sources.oauthClients.create(payload), |
| 909 | 909 | }, |
| @@ -952,7 +952,7 @@ export const createExecutorAdminToolMap = (input: { · 42 unmodified lines | ||
| 952 | 952 | tool: { |
| 953 | 953 | description: "Create a local workspace policy.", |
| 954 | 954 | inputSchema: createPolicyInputSchema, |
| 955 | − outputSchema: localWorkspacePolicyOutputSchema, | |
| 955 | + outputSchema: localScopePolicyOutputSchema, | |
| 956 | 956 | execute: (payload: CreatePolicyPayload) => |
| 957 | 957 | input.executor.policies.create(payload), |
| 958 | 958 | }, |
| @@ -962,7 +962,7 @@ export const createExecutorAdminToolMap = (input: { · 3 unmodified lines | ||
| 962 | 962 | tool: { |
| 963 | 963 | description: "Get one local workspace policy by id.", |
| 964 | 964 | inputSchema: policyIdInputSchema, |
| 965 | − outputSchema: localWorkspacePolicyOutputSchema, | |
| 965 | + outputSchema: localScopePolicyOutputSchema, | |
| 966 | 966 | execute: ({ policyId }: { policyId: string }) => |
| 967 | 967 | input.executor.policies.get(policyId), |
| 968 | 968 | }, |
| @@ -972,7 +972,7 @@ export const createExecutorAdminToolMap = (input: { · 3 unmodified lines | ||
| 972 | 972 | tool: { |
| 973 | 973 | description: "Update a local workspace policy.", |
| 974 | 974 | inputSchema: updatePolicyInputSchema, |
| 975 | − outputSchema: localWorkspacePolicyOutputSchema, | |
| 975 | + outputSchema: localScopePolicyOutputSchema, | |
| 976 | 976 | execute: ({ |
| 977 | 977 | policyId, |
| 978 | 978 | payload, |
| @@ -34,7 +34,7 @@ describe("local-config", () => { · 33 unmodified lines | ||
| 34 | 34 | join(configDirectory, "executor.jsonc"), |
| 35 | 35 | `{ |
| 36 | 36 | "runtime": "ses", |
| 37 | − // local workspace config | |
| 37 | + // local scope config | |
| 38 | 38 | "sources": { |
| 39 | 39 | "github": { |
| 40 | 40 | "kind": "openapi", |
| @@ -16,8 +16,8 @@ import { · 15 unmodified lines | ||
| 16 | 16 | } from "@executor/platform-sdk/schema"; |
| 17 | 17 | import * as Effect from "effect/Effect"; |
| 18 | 18 | import * as Schema from "effect/Schema"; |
| 19 | −import type { ExecutorWorkspaceDescriptor } from "@executor/platform-sdk"; | |
| 20 | −import type { LoadedLocalExecutorConfig } from "../../sdk/src/runtime/workspace-config"; | |
| 19 | +import type { ExecutorScopeDescriptor } from "@executor/platform-sdk"; | |
| 20 | +import type { LoadedLocalExecutorConfig } from "../../sdk/src/runtime/scope-config"; | |
| 21 | 21 | import { |
| 22 | 22 | LocalExecutorConfigDecodeError, |
| 23 | 23 | LocalFileSystemError, |
| @@ -36,7 +36,7 @@ export const encodeLocalExecutorConfig = (config: LocalExecutorConfig): string = · 12 unmodified lines | ||
| 36 | 36 | |
| 37 | 37 | export const resolveConfigRelativePath = (input: { |
| 38 | 38 | path: string; |
| 39 | − workspaceRoot: string; | |
| 39 | + scopeRoot: string; | |
| 40 | 40 | }): string => { |
| 41 | 41 | const trimmed = input.path.trim(); |
| 42 | 42 | if (trimmed.startsWith("~/")) { |
| @@ -48,10 +48,10 @@ export const resolveConfigRelativePath = (input: { · 5 unmodified lines | ||
| 48 | 48 | if (isAbsolute(trimmed)) { |
| 49 | 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 | 56 | const PROJECT_CONFIG_BASENAME = "executor.jsonc"; |
| 57 | 57 | const PROJECT_CONFIG_DIRECTORY = ".executor"; |
| @@ -52,7 +52,7 @@ describe("local-executor-state-store", () => { · 51 unmodified lines | ||
| 52 | 52 | authArtifacts: [], |
| 53 | 53 | authLeases: [], |
| 54 | 54 | sourceOauthClients: [], |
| 55 | − workspaceOauthClients: [], | |
| 55 | + scopeOauthClients: [], | |
| 56 | 56 | providerAuthGrants: [], |
| 57 | 57 | sourceAuthSessions: [], |
| 58 | 58 | secretMaterials: [], |
| @@ -20,10 +20,10 @@ import { · 19 unmodified lines | ||
| 20 | 20 | type SecretMaterial, |
| 21 | 21 | type SourceAuthSession, |
| 22 | 22 | SourceAuthSessionSchema, |
| 23 | − type WorkspaceOauthClient, | |
| 24 | − WorkspaceOauthClientSchema, | |
| 25 | − type WorkspaceSourceOauthClient, | |
| 26 | − WorkspaceSourceOauthClientSchema, | |
| 23 | + type ScopeOauthClient, | |
| 24 | + ScopeOauthClientSchema, | |
| 25 | + type ScopedSourceOauthClient, | |
| 26 | + ScopedSourceOauthClientSchema, | |
| 27 | 27 | } from "@executor/platform-sdk/schema"; |
| 28 | 28 | import * as Effect from "effect/Effect"; |
| 29 | 29 | import * as Option from "effect/Option"; |
| @@ -43,8 +43,8 @@ const LocalExecutorStateSnapshotSchema = Schema.Struct({ · 13 unmodified lines | ||
| 43 | 43 | version: Schema.Literal(LOCAL_EXECUTOR_STATE_VERSION), |
| 44 | 44 | authArtifacts: Schema.Array(AuthArtifactSchema), |
| 45 | 45 | authLeases: Schema.Array(AuthLeaseSchema), |
| 46 | − sourceOauthClients: Schema.Array(WorkspaceSourceOauthClientSchema), | |
| 47 | − workspaceOauthClients: Schema.Array(WorkspaceOauthClientSchema), | |
| 46 | + sourceOauthClients: Schema.Array(ScopedSourceOauthClientSchema), | |
| 47 | + scopeOauthClients: Schema.Array(ScopeOauthClientSchema), | |
| 48 | 48 | providerAuthGrants: Schema.Array(ProviderAuthGrantSchema), |
| 49 | 49 | sourceAuthSessions: Schema.Array(SourceAuthSessionSchema), |
| 50 | 50 | secretMaterials: Schema.Array(SecretMaterialSchema), |
| @@ -69,7 +69,7 @@ const defaultLocalExecutorStateSnapshot = (): LocalExecutorStateSnapshot => ({ · 18 unmodified lines | ||
| 69 | 69 | authArtifacts: [], |
| 70 | 70 | authLeases: [], |
| 71 | 71 | sourceOauthClients: [], |
| 72 | − workspaceOauthClients: [], | |
| 72 | + scopeOauthClients: [], | |
| 73 | 73 | providerAuthGrants: [], |
| 74 | 74 | sourceAuthSessions: [], |
| 75 | 75 | secretMaterials: [], |
| @@ -114,7 +114,7 @@ const localExecutorStatePath = ( · 38 unmodified lines | ||
| 114 | 114 | join( |
| 115 | 115 | context.homeStateDirectory, |
| 116 | 116 | "workspaces", |
| 117 | − deriveLocalInstallation(context).workspaceId, | |
| 117 | + deriveLocalInstallation(context).scopeId, | |
| 118 | 118 | LOCAL_EXECUTOR_STATE_BASENAME, |
| 119 | 119 | ); |
| 120 | 120 | |
| @@ -230,9 +230,9 @@ const mergeAuthArtifacts = ( · 109 unmodified lines | ||
| 230 | 230 | for (const artifact of imported) { |
| 231 | 231 | merged.set( |
| 232 | 232 | [ |
| 233 | − artifact.workspaceId, | |
| 233 | + artifact.scopeId, | |
| 234 | 234 | artifact.sourceId, |
| 235 | − artifact.actorAccountId ?? "", | |
| 235 | + artifact.actorScopeId ?? "", | |
| 236 | 236 | artifact.slot, |
| 237 | 237 | ].join("::"), |
| 238 | 238 | cloneValue(artifact), |
| @@ -242,9 +242,9 @@ const mergeAuthArtifacts = ( · 3 unmodified lines | ||
| 242 | 242 | for (const artifact of current) { |
| 243 | 243 | merged.set( |
| 244 | 244 | [ |
| 245 | − artifact.workspaceId, | |
| 245 | + artifact.scopeId, | |
| 246 | 246 | artifact.sourceId, |
| 247 | − artifact.actorAccountId ?? "", | |
| 247 | + artifact.actorScopeId ?? "", | |
| 248 | 248 | artifact.slot, |
| 249 | 249 | ].join("::"), |
| 250 | 250 | cloneValue(artifact), |
| @@ -255,14 +255,14 @@ const mergeAuthArtifacts = ( · 4 unmodified lines | ||
| 255 | 255 | }; |
| 256 | 256 | |
| 257 | 257 | const mergeSourceOauthClients = ( |
| 258 | − current: readonly WorkspaceSourceOauthClient[], | |
| 259 | − imported: readonly WorkspaceSourceOauthClient[], | |
| 260 | −): WorkspaceSourceOauthClient[] => { | |
| 261 | − const merged = new Map<string, WorkspaceSourceOauthClient>(); | |
| 258 | + current: readonly ScopedSourceOauthClient[], | |
| 259 | + imported: readonly ScopedSourceOauthClient[], | |
| 260 | +): ScopedSourceOauthClient[] => { | |
| 261 | + const merged = new Map<string, ScopedSourceOauthClient>(); | |
| 262 | 262 | |
| 263 | 263 | for (const oauthClient of imported) { |
| 264 | 264 | merged.set( |
| 265 | − [oauthClient.workspaceId, oauthClient.sourceId, oauthClient.providerKey].join( | |
| 265 | + [oauthClient.scopeId, oauthClient.sourceId, oauthClient.providerKey].join( | |
| 266 | 266 | "::", |
| 267 | 267 | ), |
| 268 | 268 | cloneValue(oauthClient), |
| @@ -271,7 +271,7 @@ const mergeSourceOauthClients = ( · 2 unmodified lines | ||
| 271 | 271 | |
| 272 | 272 | for (const oauthClient of current) { |
| 273 | 273 | merged.set( |
| 274 | − [oauthClient.workspaceId, oauthClient.sourceId, oauthClient.providerKey].join( | |
| 274 | + [oauthClient.scopeId, oauthClient.sourceId, oauthClient.providerKey].join( | |
| 275 | 275 | "::", |
| 276 | 276 | ), |
| 277 | 277 | cloneValue(oauthClient), |
| @@ -282,21 +282,21 @@ const mergeSourceOauthClients = ( · 4 unmodified lines | ||
| 282 | 282 | }; |
| 283 | 283 | |
| 284 | 284 | const mergeWorkspaceOauthClients = ( |
| 285 | − current: readonly WorkspaceOauthClient[], | |
| 286 | − imported: readonly WorkspaceOauthClient[], | |
| 287 | −): WorkspaceOauthClient[] => { | |
| 288 | − const merged = new Map<string, WorkspaceOauthClient>(); | |
| 285 | + current: readonly ScopeOauthClient[], | |
| 286 | + imported: readonly ScopeOauthClient[], | |
| 287 | +): ScopeOauthClient[] => { | |
| 288 | + const merged = new Map<string, ScopeOauthClient>(); | |
| 289 | 289 | |
| 290 | 290 | for (const oauthClient of imported) { |
| 291 | 291 | merged.set( |
| 292 | − [oauthClient.workspaceId, oauthClient.providerKey, oauthClient.id].join("::"), | |
| 292 | + [oauthClient.scopeId, oauthClient.providerKey, oauthClient.id].join("::"), | |
| 293 | 293 | cloneValue(oauthClient), |
| 294 | 294 | ); |
| 295 | 295 | } |
| 296 | 296 | |
| 297 | 297 | for (const oauthClient of current) { |
| 298 | 298 | merged.set( |
| 299 | − [oauthClient.workspaceId, oauthClient.providerKey, oauthClient.id].join("::"), | |
| 299 | + [oauthClient.scopeId, oauthClient.providerKey, oauthClient.id].join("::"), | |
| 300 | 300 | cloneValue(oauthClient), |
| 301 | 301 | ); |
| 302 | 302 | } |
| @@ -326,9 +326,9 @@ export const mergeImportedLocalExecutorStateSnapshot = (input: { · 23 unmodified lines | ||
| 326 | 326 | input.current.sourceOauthClients, |
| 327 | 327 | input.imported.sourceOauthClients ?? [], |
| 328 | 328 | ), |
| 329 | − workspaceOauthClients: mergeWorkspaceOauthClients( | |
| 330 | − input.current.workspaceOauthClients, | |
| 331 | − input.imported.workspaceOauthClients ?? [], | |
| 329 | + scopeOauthClients: mergeWorkspaceOauthClients( | |
| 330 | + input.current.scopeOauthClients, | |
| 331 | + input.imported.scopeOauthClients ?? [], | |
| 332 | 332 | ), |
| 333 | 333 | providerAuthGrants: mergeProviderAuthGrants( |
| 334 | 334 | input.current.providerAuthGrants, |
| @@ -440,40 +440,40 @@ export const createLocalExecutorStateStore = ( · 105 unmodified lines | ||
| 440 | 440 | |
| 441 | 441 | return { |
| 442 | 442 | authArtifacts: { |
| 443 | − listByWorkspaceId: (workspaceId: AuthArtifact["workspaceId"]) => | |
| 443 | + listByScopeId: (scopeId: AuthArtifact["scopeId"]) => | |
| 444 | 444 | stateManager.read((state) => |
| 445 | 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: { | |
| 451 | − workspaceId: AuthArtifact["workspaceId"]; | |
| 450 | + listByScopeAndSourceId: (input: { | |
| 451 | + scopeId: AuthArtifact["scopeId"]; | |
| 452 | 452 | sourceId: AuthArtifact["sourceId"]; |
| 453 | 453 | }) => |
| 454 | 454 | stateManager.read((state) => |
| 455 | 455 | sortByUpdatedAtAndIdAsc( |
| 456 | 456 | state.authArtifacts.filter( |
| 457 | 457 | (artifact) => |
| 458 | − artifact.workspaceId === input.workspaceId | |
| 458 | + artifact.scopeId === input.scopeId | |
| 459 | 459 | && artifact.sourceId === input.sourceId, |
| 460 | 460 | ), |
| 461 | 461 | ), |
| 462 | 462 | ), |
| 463 | 463 | |
| 464 | − getByWorkspaceSourceAndActor: (input: { | |
| 465 | − workspaceId: AuthArtifact["workspaceId"]; | |
| 464 | + getByScopeSourceAndActor: (input: { | |
| 465 | + scopeId: AuthArtifact["scopeId"]; | |
| 466 | 466 | sourceId: AuthArtifact["sourceId"]; |
| 467 | − actorAccountId: AuthArtifact["actorAccountId"]; | |
| 467 | + actorScopeId: AuthArtifact["actorScopeId"]; | |
| 468 | 468 | slot: AuthArtifact["slot"]; |
| 469 | 469 | }) => |
| 470 | 470 | stateManager.read((state) => { |
| 471 | 471 | const artifact = state.authArtifacts.find( |
| 472 | 472 | (candidate) => |
| 473 | − candidate.workspaceId === input.workspaceId | |
| 473 | + candidate.scopeId === input.scopeId | |
| 474 | 474 | && candidate.sourceId === input.sourceId |
| 475 | 475 | && candidate.slot === input.slot |
| 476 | − && actorEquals(candidate.actorAccountId, input.actorAccountId), | |
| 476 | + && actorEquals(candidate.actorScopeId, input.actorScopeId), | |
| 477 | 477 | ); |
| 478 | 478 | |
| 479 | 479 | return artifact ? Option.some(cloneValue(artifact)) : Option.none<AuthArtifact>(); |
| @@ -484,10 +484,10 @@ export const createLocalExecutorStateStore = ( · 4 unmodified lines | ||
| 484 | 484 | const nextArtifacts = state.authArtifacts.filter( |
| 485 | 485 | (candidate) => |
| 486 | 486 | !( |
| 487 | − candidate.workspaceId === artifact.workspaceId | |
| 487 | + candidate.scopeId === artifact.scopeId | |
| 488 | 488 | && candidate.sourceId === artifact.sourceId |
| 489 | 489 | && candidate.slot === artifact.slot |
| 490 | − && actorEquals(candidate.actorAccountId, artifact.actorAccountId) | |
| 490 | + && actorEquals(candidate.actorScopeId, artifact.actorScopeId) | |
| 491 | 491 | ), |
| 492 | 492 | ); |
| 493 | 493 | nextArtifacts.push(cloneValue(artifact)); |
| @@ -501,18 +501,18 @@ export const createLocalExecutorStateStore = ( · 7 unmodified lines | ||
| 501 | 501 | } satisfies StateMutationResult<void>; |
| 502 | 502 | }), |
| 503 | 503 | |
| 504 | − removeByWorkspaceSourceAndActor: (input: { | |
| 505 | − workspaceId: AuthArtifact["workspaceId"]; | |
| 504 | + removeByScopeSourceAndActor: (input: { | |
| 505 | + scopeId: AuthArtifact["scopeId"]; | |
| 506 | 506 | sourceId: AuthArtifact["sourceId"]; |
| 507 | − actorAccountId: AuthArtifact["actorAccountId"]; | |
| 507 | + actorScopeId: AuthArtifact["actorScopeId"]; | |
| 508 | 508 | slot?: AuthArtifact["slot"]; |
| 509 | 509 | }) => |
| 510 | 510 | stateManager.mutate((state) => { |
| 511 | 511 | const nextArtifacts = state.authArtifacts.filter( |
| 512 | 512 | (candidate) => |
| 513 | − candidate.workspaceId !== input.workspaceId | |
| 513 | + candidate.scopeId !== input.scopeId | |
| 514 | 514 | || candidate.sourceId !== input.sourceId |
| 515 | − || !actorEquals(candidate.actorAccountId, input.actorAccountId) | |
| 515 | + || !actorEquals(candidate.actorScopeId, input.actorScopeId) | |
| 516 | 516 | || (input.slot !== undefined && candidate.slot !== input.slot), |
| 517 | 517 | ); |
| 518 | 518 | |
| @@ -525,14 +525,14 @@ export const createLocalExecutorStateStore = ( · 6 unmodified lines | ||
| 525 | 525 | } satisfies StateMutationResult<boolean>; |
| 526 | 526 | }), |
| 527 | 527 | |
| 528 | − removeByWorkspaceAndSourceId: (input: { | |
| 529 | − workspaceId: AuthArtifact["workspaceId"]; | |
| 528 | + removeByScopeAndSourceId: (input: { | |
| 529 | + scopeId: AuthArtifact["scopeId"]; | |
| 530 | 530 | sourceId: AuthArtifact["sourceId"]; |
| 531 | 531 | }) => |
| 532 | 532 | stateManager.mutate((state) => { |
| 533 | 533 | const nextArtifacts = state.authArtifacts.filter( |
| 534 | 534 | (candidate) => |
| 535 | − candidate.workspaceId !== input.workspaceId | |
| 535 | + candidate.scopeId !== input.scopeId | |
| 536 | 536 | || candidate.sourceId !== input.sourceId, |
| 537 | 537 | ); |
| 538 | 538 | |
| @@ -591,30 +591,30 @@ export const createLocalExecutorStateStore = ( · 52 unmodified lines | ||
| 591 | 591 | }, |
| 592 | 592 | |
| 593 | 593 | sourceOauthClients: { |
| 594 | − getByWorkspaceSourceAndProvider: (input: { | |
| 595 | − workspaceId: WorkspaceSourceOauthClient["workspaceId"]; | |
| 596 | − sourceId: WorkspaceSourceOauthClient["sourceId"]; | |
| 594 | + getByScopeSourceAndProvider: (input: { | |
| 595 | + scopeId: ScopedSourceOauthClient["scopeId"]; | |
| 596 | + sourceId: ScopedSourceOauthClient["sourceId"]; | |
| 597 | 597 | providerKey: string; |
| 598 | 598 | }) => |
| 599 | 599 | stateManager.read((state) => { |
| 600 | 600 | const oauthClient = state.sourceOauthClients.find( |
| 601 | 601 | (candidate) => |
| 602 | − candidate.workspaceId === input.workspaceId | |
| 602 | + candidate.scopeId === input.scopeId | |
| 603 | 603 | && candidate.sourceId === input.sourceId |
| 604 | 604 | && candidate.providerKey === input.providerKey, |
| 605 | 605 | ); |
| 606 | 606 | |
| 607 | 607 | return oauthClient |
| 608 | 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 | 613 | stateManager.mutate((state) => { |
| 614 | 614 | const nextOauthClients = state.sourceOauthClients.filter( |
| 615 | 615 | (candidate) => |
| 616 | 616 | !( |
| 617 | − candidate.workspaceId === oauthClient.workspaceId | |
| 617 | + candidate.scopeId === oauthClient.scopeId | |
| 618 | 618 | && candidate.sourceId === oauthClient.sourceId |
| 619 | 619 | && candidate.providerKey === oauthClient.providerKey |
| 620 | 620 | ), |
| @@ -630,14 +630,14 @@ export const createLocalExecutorStateStore = ( · 9 unmodified lines | ||
| 630 | 630 | } satisfies StateMutationResult<void>; |
| 631 | 631 | }), |
| 632 | 632 | |
| 633 | − removeByWorkspaceAndSourceId: (input: { | |
| 634 | − workspaceId: WorkspaceSourceOauthClient["workspaceId"]; | |
| 635 | − sourceId: WorkspaceSourceOauthClient["sourceId"]; | |
| 633 | + removeByScopeAndSourceId: (input: { | |
| 634 | + scopeId: ScopedSourceOauthClient["scopeId"]; | |
| 635 | + sourceId: ScopedSourceOauthClient["sourceId"]; | |
| 636 | 636 | }) => |
| 637 | 637 | stateManager.mutate((state) => { |
| 638 | 638 | const nextOauthClients = state.sourceOauthClients.filter( |
| 639 | 639 | (candidate) => |
| 640 | − candidate.workspaceId !== input.workspaceId | |
| 640 | + candidate.scopeId !== input.scopeId | |
| 641 | 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: { | |
| 655 | − listByWorkspaceAndProvider: (input: { | |
| 656 | − workspaceId: WorkspaceOauthClient["workspaceId"]; | |
| 654 | + scopeOauthClients: { | |
| 655 | + listByScopeAndProvider: (input: { | |
| 656 | + scopeId: ScopeOauthClient["scopeId"]; | |
| 657 | 657 | providerKey: string; |
| 658 | 658 | }) => |
| 659 | 659 | stateManager.read((state) => |
| 660 | 660 | sortByUpdatedAtAndIdAsc( |
| 661 | − state.workspaceOauthClients.filter( | |
| 661 | + state.scopeOauthClients.filter( | |
| 662 | 662 | (candidate) => |
| 663 | − candidate.workspaceId === input.workspaceId | |
| 663 | + candidate.scopeId === input.scopeId | |
| 664 | 664 | && candidate.providerKey === input.providerKey, |
| 665 | 665 | ), |
| 666 | 666 | ), |
| 667 | 667 | ), |
| 668 | 668 | |
| 669 | − getById: (id: WorkspaceOauthClient["id"]) => | |
| 669 | + getById: (id: ScopeOauthClient["id"]) => | |
| 670 | 670 | stateManager.read((state) => { |
| 671 | − const oauthClient = state.workspaceOauthClients.find( | |
| 671 | + const oauthClient = state.scopeOauthClients.find( | |
| 672 | 672 | (candidate) => candidate.id === id, |
| 673 | 673 | ); |
| 674 | 674 | |
| 675 | 675 | return oauthClient |
| 676 | 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 | 681 | stateManager.mutate((state) => { |
| 682 | − const nextOauthClients = state.workspaceOauthClients.filter( | |
| 682 | + const nextOauthClients = state.scopeOauthClients.filter( | |
| 683 | 683 | (candidate) => candidate.id !== oauthClient.id, |
| 684 | 684 | ); |
| 685 | 685 | nextOauthClients.push(cloneValue(oauthClient)); |
| @@ -687,50 +687,50 @@ export const createLocalExecutorStateStore = ( · 1 unmodified line | ||
| 687 | 687 | return { |
| 688 | 688 | state: { |
| 689 | 689 | ...state, |
| 690 | − workspaceOauthClients: nextOauthClients, | |
| 690 | + scopeOauthClients: nextOauthClients, | |
| 691 | 691 | }, |
| 692 | 692 | value: undefined, |
| 693 | 693 | } satisfies StateMutationResult<void>; |
| 694 | 694 | }), |
| 695 | 695 | |
| 696 | − removeById: (id: WorkspaceOauthClient["id"]) => | |
| 696 | + removeById: (id: ScopeOauthClient["id"]) => | |
| 697 | 697 | stateManager.mutate((state) => { |
| 698 | − const nextOauthClients = state.workspaceOauthClients.filter( | |
| 698 | + const nextOauthClients = state.scopeOauthClients.filter( | |
| 699 | 699 | (candidate) => candidate.id !== id, |
| 700 | 700 | ); |
| 701 | 701 | |
| 702 | 702 | return { |
| 703 | 703 | state: { |
| 704 | 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 | 708 | } satisfies StateMutationResult<boolean>; |
| 709 | 709 | }), |
| 710 | 710 | }, |
| 711 | 711 | |
| 712 | 712 | providerAuthGrants: { |
| 713 | − listByWorkspaceId: (workspaceId: ProviderAuthGrant["workspaceId"]) => | |
| 713 | + listByScopeId: (scopeId: ProviderAuthGrant["scopeId"]) => | |
| 714 | 714 | stateManager.read((state) => |
| 715 | 715 | sortByUpdatedAtAndIdAsc( |
| 716 | 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: { | |
| 723 | − workspaceId: ProviderAuthGrant["workspaceId"]; | |
| 724 | − actorAccountId: ProviderAuthGrant["actorAccountId"]; | |
| 722 | + listByScopeActorAndProvider: (input: { | |
| 723 | + scopeId: ProviderAuthGrant["scopeId"]; | |
| 724 | + actorScopeId: ProviderAuthGrant["actorScopeId"]; | |
| 725 | 725 | providerKey: string; |
| 726 | 726 | }) => |
| 727 | 727 | stateManager.read((state) => |
| 728 | 728 | sortByUpdatedAtAndIdAsc( |
| 729 | 729 | state.providerAuthGrants.filter( |
| 730 | 730 | (grant) => |
| 731 | − grant.workspaceId === input.workspaceId | |
| 731 | + grant.scopeId === input.scopeId | |
| 732 | 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 | 782 | listAll: () => |
| 783 | 783 | stateManager.read((state) => sortByUpdatedAtAndIdAsc(state.sourceAuthSessions)), |
| 784 | 784 | |
| 785 | − listByWorkspaceId: (workspaceId: SourceAuthSession["workspaceId"]) => | |
| 785 | + listByScopeId: (scopeId: SourceAuthSession["scopeId"]) => | |
| 786 | 786 | stateManager.read((state) => |
| 787 | 787 | sortByUpdatedAtAndIdAsc( |
| 788 | 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 | 811 | : Option.none<SourceAuthSession>(); |
| 812 | 812 | }), |
| 813 | 813 | |
| 814 | − getPendingByWorkspaceSourceAndActor: (input: { | |
| 815 | − workspaceId: SourceAuthSession["workspaceId"]; | |
| 814 | + getPendingByScopeSourceAndActor: (input: { | |
| 815 | + scopeId: SourceAuthSession["scopeId"]; | |
| 816 | 816 | sourceId: SourceAuthSession["sourceId"]; |
| 817 | − actorAccountId: SourceAuthSession["actorAccountId"]; | |
| 817 | + actorScopeId: SourceAuthSession["actorScopeId"]; | |
| 818 | 818 | credentialSlot?: SourceAuthSession["credentialSlot"]; |
| 819 | 819 | }) => |
| 820 | 820 | stateManager.read((state) => { |
| 821 | 821 | const session = sortByUpdatedAtAndIdAsc( |
| 822 | 822 | state.sourceAuthSessions.filter( |
| 823 | 823 | (candidate) => |
| 824 | − candidate.workspaceId === input.workspaceId | |
| 824 | + candidate.scopeId === input.scopeId | |
| 825 | 825 | && candidate.sourceId === input.sourceId |
| 826 | 826 | && candidate.status === "pending" |
| 827 | − && actorEquals(candidate.actorAccountId, input.actorAccountId) | |
| 827 | + && actorEquals(candidate.actorScopeId, input.actorScopeId) | |
| 828 | 828 | && (input.credentialSlot === undefined |
| 829 | 829 | || candidate.credentialSlot === input.credentialSlot), |
| 830 | 830 | ), |
| @@ -846,7 +846,7 @@ export const createLocalExecutorStateStore = ( · 15 unmodified lines | ||
| 846 | 846 | |
| 847 | 847 | update: ( |
| 848 | 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 | 851 | stateManager.mutate((state) => { |
| 852 | 852 | let updated: SourceAuthSession | null = null; |
| @@ -887,14 +887,14 @@ export const createLocalExecutorStateStore = ( · 34 unmodified lines | ||
| 887 | 887 | } satisfies StateMutationResult<void>; |
| 888 | 888 | }), |
| 889 | 889 | |
| 890 | − removeByWorkspaceAndSourceId: ( | |
| 891 | − workspaceId: SourceAuthSession["workspaceId"], | |
| 890 | + removeByScopeAndSourceId: ( | |
| 891 | + scopeId: SourceAuthSession["scopeId"], | |
| 892 | 892 | sourceId: SourceAuthSession["sourceId"], |
| 893 | 893 | ) => |
| 894 | 894 | stateManager.mutate((state) => { |
| 895 | 895 | const nextSessions = state.sourceAuthSessions.filter( |
| 896 | 896 | (candidate) => |
| 897 | − candidate.workspaceId !== workspaceId || candidate.sourceId !== sourceId, | |
| 897 | + candidate.scopeId !== scopeId || candidate.sourceId !== sourceId, | |
| 898 | 898 | ); |
| 899 | 899 | |
| 900 | 900 | return { |
| @@ -993,14 +993,14 @@ export const createLocalExecutorStateStore = ( · 92 unmodified lines | ||
| 993 | 993 | : Option.none<Execution>(); |
| 994 | 994 | }), |
| 995 | 995 | |
| 996 | − getByWorkspaceAndId: ( | |
| 997 | − workspaceId: Execution["workspaceId"], | |
| 996 | + getByScopeAndId: ( | |
| 997 | + scopeId: Execution["scopeId"], | |
| 998 | 998 | executionId: Execution["id"], |
| 999 | 999 | ) => |
| 1000 | 1000 | stateManager.read((state) => { |
| 1001 | 1001 | const execution = state.executions.find( |
| 1002 | 1002 | (candidate) => |
| 1003 | − candidate.workspaceId === workspaceId && candidate.id === executionId, | |
| 1003 | + candidate.scopeId === scopeId && candidate.id === executionId, | |
| 1004 | 1004 | ); |
| 1005 | 1005 | return execution |
| 1006 | 1006 | ? Option.some(cloneValue(execution)) |
| @@ -1019,7 +1019,7 @@ export const createLocalExecutorStateStore = ( · 12 unmodified lines | ||
| 1019 | 1019 | update: ( |
| 1020 | 1020 | executionId: Execution["id"], |
| 1021 | 1021 | patch: Partial< |
| 1022 | − Omit<Execution, "id" | "workspaceId" | "createdByAccountId" | "createdAt"> | |
| 1022 | + Omit<Execution, "id" | "scopeId" | "createdByAccountId" | "createdAt"> | |
| 1023 | 1023 | >, |
| 1024 | 1024 | ) => |
| 1025 | 1025 | stateManager.mutate((state) => { |
| @@ -10,7 +10,7 @@ import { · 9 unmodified lines | ||
| 10 | 10 | type ExecutorBackendServices, |
| 11 | 11 | type ExecutorLocalToolBackend, |
| 12 | 12 | type ExecutorSourceTypeDeclarationsBackend, |
| 13 | − type ExecutorWorkspaceDescriptor, | |
| 13 | + type ExecutorScopeDescriptor, | |
| 14 | 14 | } from "@executor/platform-sdk"; |
| 15 | 15 | import type { |
| 16 | 16 | LocalExecutorConfig, |
| @@ -198,11 +198,11 @@ const createBoundSourceTypeDeclarationsRefresher = ( · 181 unmodified lines | ||
| 198 | 198 | }), |
| 199 | 199 | }); |
| 200 | 200 | |
| 201 | −const toExecutorWorkspaceContext = ( | |
| 201 | +const toExecutorScopeContext = ( | |
| 202 | 202 | context: ResolvedLocalWorkspaceContext, |
| 203 | −): ExecutorWorkspaceDescriptor => ({ | |
| 204 | − workspaceName: context.workspaceName, | |
| 205 | − workspaceRoot: context.workspaceRoot, | |
| 203 | +): ExecutorScopeDescriptor => ({ | |
| 204 | + scopeName: context.workspaceName, | |
| 205 | + scopeRoot: context.workspaceRoot, | |
| 206 | 206 | metadata: { |
| 207 | 207 | kind: "file", |
| 208 | 208 | configDirectory: context.configDirectory, |
| @@ -248,11 +248,11 @@ export const createLocalExecutorServicesEffect = ( · 39 unmodified lines | ||
| 248 | 248 | }); |
| 249 | 249 | |
| 250 | 250 | return { |
| 251 | − workspace: toExecutorWorkspaceContext(workspaceContext), | |
| 251 | + scope: toExecutorScopeContext(workspaceContext), | |
| 252 | 252 | storage: { |
| 253 | 253 | installation: createBoundInstallationStore(workspaceContext), |
| 254 | − workspaceConfig: workspaceConfigStore, | |
| 255 | − workspaceState: createBoundWorkspaceStateStore( | |
| 254 | + scopeConfig: workspaceConfigStore, | |
| 255 | + scopeState: createBoundWorkspaceStateStore( | |
| 256 | 256 | workspaceContext, |
| 257 | 257 | fileSystem, |
| 258 | 258 | ), |
| @@ -42,8 +42,8 @@ describe("local-installation", () => { · 41 unmodified lines | ||
| 42 | 42 | const installation = runtime.localInstallation; |
| 43 | 43 | const fs = yield* FileSystem.FileSystem; |
| 44 | 44 | |
| 45 | − expect(installation.accountId).toBe("acc_local_default"); | |
| 46 | − expect(installation.workspaceId.startsWith("ws_local_")).toBe(true); | |
| 45 | + expect(installation.actorScopeId).toBe("acc_local_default"); | |
| 46 | + expect(installation.scopeId.startsWith("ws_local_")).toBe(true); | |
| 47 | 47 | expect(yield* fs.exists(join(workspaceRoot, ".executor", "executor.jsonc"))).toBe(false); |
| 48 | 48 | }).pipe(Effect.provide(NodeFileSystem.layer)), |
| 49 | 49 | 60_000, |
| @@ -63,8 +63,8 @@ describe("local-installation", () => { · 13 unmodified lines | ||
| 63 | 63 | context, |
| 64 | 64 | }); |
| 65 | 65 | |
| 66 | − expect(second.accountId).toBe(first.accountId); | |
| 67 | − expect(second.workspaceId).toBe(first.workspaceId); | |
| 66 | + expect(second.actorScopeId).toBe(first.actorScopeId); | |
| 67 | + expect(second.scopeId).toBe(first.scopeId); | |
| 68 | 68 | }).pipe(Effect.provide(NodeFileSystem.layer)), |
| 69 | 69 | ); |
| 70 | 70 | }); |
| @@ -1,15 +1,14 @@ | ||
| 1 | 1 | import { createHash } from "node:crypto"; |
| 2 | 2 | |
| 3 | 3 | import { |
| 4 | − AccountIdSchema, | |
| 5 | − WorkspaceIdSchema, | |
| 4 | + ScopeIdSchema, | |
| 6 | 5 | type LocalInstallation, |
| 7 | 6 | } from "@executor/platform-sdk/schema"; |
| 8 | 7 | import * as Effect from "effect/Effect"; |
| 9 | 8 | |
| 10 | 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 | 13 | const stableHash = (value: string): string => |
| 15 | 14 | createHash("sha256").update(value).digest("hex").slice(0, 16); |
| @@ -18,15 +17,19 @@ const normalizeSlashPath = (value: string): string => · 2 unmodified lines | ||
| 18 | 17 | value.replaceAll("\\", "/"); |
| 19 | 18 | |
| 20 | 19 | const deriveWorkspaceId = (context: ResolvedLocalWorkspaceContext) => |
| 21 | − WorkspaceIdSchema.make( | |
| 20 | + ScopeIdSchema.make( | |
| 22 | 21 | `ws_local_${stableHash(normalizeSlashPath(context.workspaceRoot))}`, |
| 23 | 22 | ); |
| 24 | 23 | |
| 25 | 24 | export const deriveLocalInstallation = ( |
| 26 | 25 | context: ResolvedLocalWorkspaceContext, |
| 27 | 26 | ): LocalInstallation => ({ |
| 28 | − accountId: LOCAL_ACCOUNT_ID, | |
| 29 | − workspaceId: deriveWorkspaceId(context), | |
| 27 | + actorScopeId: LOCAL_ACCOUNT_ID, | |
| 28 | + scopeId: deriveWorkspaceId(context), | |
| 29 | + resolutionScopeIds: [ | |
| 30 | + deriveWorkspaceId(context), | |
| 31 | + LOCAL_ACCOUNT_ID, | |
| 32 | + ], | |
| 30 | 33 | }); |
| 31 | 34 | |
| 32 | 35 | export const loadLocalInstallation = ( |
| @@ -28,9 +28,9 @@ import { · 27 unmodified lines | ||
| 28 | 28 | type StoreSecretMaterial, |
| 29 | 29 | type DeleteSecretMaterial, |
| 30 | 30 | type UpdateSecretMaterial, |
| 31 | −} from "../../sdk/src/runtime/workspace/secret-material-providers"; | |
| 32 | −import { fromConfigSecretProviderId } from "../../sdk/src/runtime/workspace/config-secrets"; | |
| 33 | −import { getRuntimeLocalWorkspaceOption } from "../../sdk/src/runtime/workspace/runtime-context"; | |
| 31 | +} from "../../sdk/src/runtime/scope/secret-material-providers"; | |
| 32 | +import { fromConfigSecretProviderId } from "../../sdk/src/runtime/scope/config-secrets"; | |
| 33 | +import { getRuntimeLocalScopeOption } from "../../sdk/src/runtime/scope/runtime-context"; | |
| 34 | 34 | import { |
| 35 | 35 | ExecutorStateStore, |
| 36 | 36 | type ExecutorStateStoreShape, |
| @@ -876,7 +876,7 @@ const readFileSecretValue = (input: { · 839 unmodified lines | ||
| 876 | 876 | const fs = yield* FileSystem.FileSystem; |
| 877 | 877 | const resolvedPath = resolveConfigRelativePath({ |
| 878 | 878 | path: input.provider.path, |
| 879 | − workspaceRoot: input.workspaceRoot, | |
| 879 | + scopeRoot: input.workspaceRoot, | |
| 880 | 880 | }); |
| 881 | 881 | const raw = yield* fs.readFileString(resolvedPath, "utf8").pipe( |
| 882 | 882 | Effect.mapError(toError), |
| @@ -1140,14 +1140,14 @@ const resolveRuntimeSecretMaterialConfig = (input: { · 257 unmodified lines | ||
| 1140 | 1140 | workspaceRoot?: string | null; |
| 1141 | 1141 | }) => |
| 1142 | 1142 | Effect.gen(function* () { |
| 1143 | − const runtimeLocalWorkspace = yield* getRuntimeLocalWorkspaceOption(); | |
| 1143 | + const runtimeLocalScope = yield* getRuntimeLocalScopeOption(); | |
| 1144 | 1144 | |
| 1145 | 1145 | return { |
| 1146 | 1146 | localConfig: input.localConfig |
| 1147 | − ?? runtimeLocalWorkspace?.loadedConfig.config | |
| 1147 | + ?? runtimeLocalScope?.loadedConfig.config | |
| 1148 | 1148 | ?? null, |
| 1149 | 1149 | workspaceRoot: input.workspaceRoot |
| 1150 | − ?? runtimeLocalWorkspace?.workspace.workspaceRoot | |
| 1150 | + ?? runtimeLocalScope?.scope.scopeRoot | |
| 1151 | 1151 | ?? null, |
| 1152 | 1152 | }; |
| 1153 | 1153 | }); |
| @@ -7,7 +7,7 @@ import * as Effect from "effect/Effect"; · 6 unmodified lines | ||
| 7 | 7 | |
| 8 | 8 | import { |
| 9 | 9 | SourceIdSchema, |
| 10 | − WorkspaceIdSchema, | |
| 10 | + ScopeIdSchema, | |
| 11 | 11 | type Source, |
| 12 | 12 | } from "@executor/platform-sdk/schema"; |
| 13 | 13 | |
| @@ -52,7 +52,7 @@ const makeContext = (): Effect.Effect< · 38 unmodified lines | ||
| 52 | 52 | |
| 53 | 53 | const makeSource = (): Source => ({ |
| 54 | 54 | id: SourceIdSchema.make("src_test"), |
| 55 | − workspaceId: WorkspaceIdSchema.make("ws_test"), | |
| 55 | + scopeId: ScopeIdSchema.make("ws_test"), | |
| 56 | 56 | name: "Test Source", |
| 57 | 57 | kind: "openapi", |
| 58 | 58 | endpoint: "https://example.com/api", |
| @@ -7,7 +7,7 @@ import * as Effect from "effect/Effect"; · 6 unmodified lines | ||
| 7 | 7 | |
| 8 | 8 | import { |
| 9 | 9 | SourceIdSchema, |
| 10 | − WorkspaceIdSchema, | |
| 10 | + ScopeIdSchema, | |
| 11 | 11 | type Source, |
| 12 | 12 | } from "@executor/platform-sdk/schema"; |
| 13 | 13 | |
| @@ -21,7 +21,6 @@ import { · 7 unmodified lines | ||
| 21 | 21 | ExecutableIdSchema, |
| 22 | 22 | ResourceIdSchema, |
| 23 | 23 | ResponseSetIdSchema, |
| 24 | − ScopeIdSchema, | |
| 25 | 24 | ShapeSymbolIdSchema, |
| 26 | 25 | } from "@executor/ir/ids"; |
| 27 | 26 | import type { CatalogV1, ProvenanceRef } from "@executor/ir/model"; |
| @@ -397,7 +396,7 @@ const makeSource = (input: { · 369 unmodified lines | ||
| 397 | 396 | status?: Source["status"]; |
| 398 | 397 | }): Source => ({ |
| 399 | 398 | id: SourceIdSchema.make(input.id), |
| 400 | − workspaceId: WorkspaceIdSchema.make("ws_test"), | |
| 399 | + scopeId: ScopeIdSchema.make("ws_test"), | |
| 401 | 400 | name: input.id, |
| 402 | 401 | kind: "graphql", |
| 403 | 402 | endpoint: "https://api.linear.app/graphql", |
| @@ -3,11 +3,11 @@ import { FileSystem } from "@effect/platform"; · 2 unmodified lines | ||
| 3 | 3 | import * as Effect from "effect/Effect"; |
| 4 | 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 | 7 | import { |
| 8 | − defaultLocalWorkspaceState, | |
| 9 | − LocalWorkspaceStateSchema, | |
| 10 | −} from "../../sdk/src/runtime/workspace-state"; | |
| 8 | + defaultLocalScopeState, | |
| 9 | + LocalScopeStateSchema, | |
| 10 | +} from "../../sdk/src/runtime/scope-state"; | |
| 11 | 11 | import type { ResolvedLocalWorkspaceContext } from "./config"; |
| 12 | 12 | import { |
| 13 | 13 | LocalFileSystemError, |
| @@ -17,7 +17,7 @@ import { · 3 unmodified lines | ||
| 17 | 17 | |
| 18 | 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 | 22 | const mapFileSystemError = (path: string, action: string) => (cause: unknown) => |
| 23 | 23 | new LocalFileSystemError({ |
| @@ -34,7 +34,7 @@ export const localWorkspaceStatePath = ( · 10 unmodified lines | ||
| 34 | 34 | export const loadLocalWorkspaceState = ( |
| 35 | 35 | context: ResolvedLocalWorkspaceContext, |
| 36 | 36 | ): Effect.Effect< |
| 37 | − LocalWorkspaceState, | |
| 37 | + LocalScopeState, | |
| 38 | 38 | LocalFileSystemError | LocalWorkspaceStateDecodeError, |
| 39 | 39 | FileSystem.FileSystem |
| 40 | 40 | > => |
| @@ -45,7 +45,7 @@ export const loadLocalWorkspaceState = ( · 4 unmodified lines | ||
| 45 | 45 | Effect.mapError(mapFileSystemError(path, "check workspace state path")), |
| 46 | 46 | ); |
| 47 | 47 | if (!exists) { |
| 48 | − return defaultLocalWorkspaceState(); | |
| 48 | + return defaultLocalScopeState(); | |
| 49 | 49 | } |
| 50 | 50 | |
| 51 | 51 | const content = yield* fs.readFileString(path, "utf8").pipe( |
| @@ -55,7 +55,7 @@ export const loadLocalWorkspaceState = ( · 3 unmodified lines | ||
| 55 | 55 | try: () => decodeLocalWorkspaceState(JSON.parse(content) as unknown), |
| 56 | 56 | catch: (cause) => |
| 57 | 57 | new LocalWorkspaceStateDecodeError({ |
| 58 | − message: `Invalid local workspace state at ${path}: ${unknownLocalErrorDetails(cause)}`, | |
| 58 | + message: `Invalid local scope state at ${path}: ${unknownLocalErrorDetails(cause)}`, | |
| 59 | 59 | path, |
| 60 | 60 | details: unknownLocalErrorDetails(cause), |
| 61 | 61 | }), |
| @@ -64,7 +64,7 @@ export const loadLocalWorkspaceState = ( · 2 unmodified lines | ||
| 64 | 64 | |
| 65 | 65 | export const writeLocalWorkspaceState = (input: { |
| 66 | 66 | context: ResolvedLocalWorkspaceContext; |
| 67 | − state: LocalWorkspaceState; | |
| 67 | + state: LocalScopeState; | |
| 68 | 68 | }): Effect.Effect<void, LocalFileSystemError, FileSystem.FileSystem> => |
| 69 | 69 | Effect.gen(function* () { |
| 70 | 70 | const fs = yield* FileSystem.FileSystem; |
| @@ -42,6 +42,7 @@ · 41 unmodified lines | ||
| 42 | 42 | }, |
| 43 | 43 | "devDependencies": { |
| 44 | 44 | "@effect/vitest": "catalog:", |
| 45 | + "@executor/effect-test-utils": "workspace:*", | |
| 45 | 46 | "@modelcontextprotocol/sdk": "^1.26.0", |
| 46 | 47 | "@types/node": "catalog:", |
| 47 | 48 | "bun-types": "catalog:", |
| @@ -6,8 +6,8 @@ import { · 5 unmodified lines | ||
| 6 | 6 | type BoundLocalToolRuntimeLoader, |
| 7 | 7 | type BoundSourceArtifactStore, |
| 8 | 8 | type BoundSourceTypeDeclarationsRefresher, |
| 9 | − type BoundWorkspaceConfigStore, | |
| 10 | − type BoundWorkspaceStateStore, | |
| 9 | + type BoundScopeConfigStore, | |
| 10 | + type BoundScopeStateStore, | |
| 11 | 11 | type ExecutorRuntime, |
| 12 | 12 | type ExecutorRuntimeOptions, |
| 13 | 13 | type RuntimeInstanceConfigService, |
| @@ -15,13 +15,13 @@ import { · 1 unmodified line | ||
| 15 | 15 | type RuntimeSecretMaterialServices, |
| 16 | 16 | } from "./runtime"; |
| 17 | 17 | import type { |
| 18 | − ExecutorWorkspaceContext, | |
| 19 | − ExecutorWorkspaceDescriptor, | |
| 20 | −} from "./workspace"; | |
| 18 | + ExecutorScopeContext, | |
| 19 | + ExecutorScopeDescriptor, | |
| 20 | +} from "./scope"; | |
| 21 | 21 | export type { |
| 22 | − ExecutorWorkspaceContext, | |
| 23 | − ExecutorWorkspaceDescriptor, | |
| 24 | −} from "./workspace"; | |
| 22 | + ExecutorScopeContext, | |
| 23 | + ExecutorScopeDescriptor, | |
| 24 | +} from "./scope"; | |
| 25 | 25 | |
| 26 | 26 | export type ExecutorBackend = { |
| 27 | 27 | createRuntime: ( |
| @@ -30,8 +30,8 @@ export type ExecutorBackend = { · 2 unmodified lines | ||
| 30 | 30 | }; |
| 31 | 31 | |
| 32 | 32 | export type ExecutorInstallationBackend = BoundInstallationStore; |
| 33 | −export type ExecutorWorkspaceConfigBackend = BoundWorkspaceConfigStore; | |
| 34 | −export type ExecutorWorkspaceStateBackend = BoundWorkspaceStateStore; | |
| 33 | +export type ExecutorScopeConfigBackend = BoundScopeConfigStore; | |
| 34 | +export type ExecutorScopeStateBackend = BoundScopeStateStore; | |
| 35 | 35 | export type ExecutorSourceArtifactBackend = BoundSourceArtifactStore; |
| 36 | 36 | export type ExecutorStateBackend = import("./runtime").ExecutorStateStoreShape; |
| 37 | 37 | export type ExecutorLocalToolBackend = BoundLocalToolRuntimeLoader; |
| @@ -42,8 +42,8 @@ export type ExecutorInstanceConfigBackend = RuntimeInstanceConfigService; · 4 unmodified lines | ||
| 42 | 42 | |
| 43 | 43 | export type ExecutorStorageBackend = { |
| 44 | 44 | installation: ExecutorInstallationBackend; |
| 45 | − workspaceConfig: ExecutorWorkspaceConfigBackend; | |
| 46 | − workspaceState: ExecutorWorkspaceStateBackend; | |
| 45 | + scopeConfig: ExecutorScopeConfigBackend; | |
| 46 | + scopeState: ExecutorScopeStateBackend; | |
| 47 | 47 | sourceArtifacts: ExecutorSourceArtifactBackend; |
| 48 | 48 | executorState: ExecutorStateBackend; |
| 49 | 49 | secretMaterial: ExecutorSecretMaterialBackend; |
| @@ -51,7 +51,7 @@ export type ExecutorStorageBackend = { · 1 unmodified line | ||
| 51 | 51 | }; |
| 52 | 52 | |
| 53 | 53 | export type ExecutorBackendServices = { |
| 54 | − workspace: ExecutorWorkspaceDescriptor; | |
| 54 | + scope: ExecutorScopeDescriptor; | |
| 55 | 55 | storage: ExecutorStorageBackend; |
| 56 | 56 | instanceConfig: ExecutorInstanceConfigBackend; |
| 57 | 57 | localTools?: ExecutorLocalToolBackend; |
| @@ -68,7 +68,7 @@ export const createExecutorBackend = (input: { · 10 unmodified lines | ||
| 68 | 68 | createExecutorRuntimeFromServices({ |
| 69 | 69 | ...options, |
| 70 | 70 | services: { |
| 71 | − workspace: services.workspace, | |
| 71 | + scope: services.scope, | |
| 72 | 72 | storage: services.storage satisfies RuntimeStorageServices, |
| 73 | 73 | localToolRuntimeLoader: services.localTools, |
| 74 | 74 | sourceTypeDeclarationsRefresher: services.sourceTypeDeclarations, |
| @@ -1,4 +1,6 @@ | ||
| 1 | −import { HttpApiSchema } from "@effect/platform"; | |
| 1 | +import { | |
| 2 | + HttpApiSchema, | |
| 3 | +} from "@effect/platform"; | |
| 2 | 4 | import * as Schema from "effect/Schema"; |
| 3 | 5 | |
| 4 | 6 | export class ControlPlaneBadRequestError extends Schema.TaggedError<ControlPlaneBadRequestError>()( |
| @@ -1,6 +1,8 @@ | ||
| 1 | 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 | 7 | export const CreateExecutionPayloadSchema = Schema.Struct({ |
| 6 | 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 | 1 | import * as Effect from "effect/Effect"; |
| 2 | 2 | |
| 3 | 3 | import type { |
| 4 | − AccountId, | |
| 4 | + ScopeId, | |
| 5 | 5 | Execution, |
| 6 | 6 | ExecutionEnvelope, |
| 7 | 7 | ExecutionInteraction, |
| 8 | 8 | LocalInstallation, |
| 9 | − LocalWorkspacePolicy, | |
| 9 | + LocalScopePolicy, | |
| 10 | 10 | ProviderAuthGrant, |
| 11 | 11 | Source, |
| 12 | − WorkspaceId, | |
| 13 | − WorkspaceOauthClient, | |
| 12 | + ScopeOauthClient, | |
| 13 | +} from "./schema"; | |
| 14 | +import { | |
| 15 | + ExecutionIdSchema, | |
| 14 | 16 | } from "./schema"; |
| 15 | −import { ExecutionIdSchema } from "./schema"; | |
| 16 | −import type { CreateExecutionPayload, ResumeExecutionPayload } from "./executions/contracts"; | |
| 17 | +import type { | |
| 18 | + CreateExecutionPayload, | |
| 19 | + ResumeExecutionPayload, | |
| 20 | +} from "./executions/contracts"; | |
| 17 | 21 | import type { |
| 18 | 22 | CreateSecretPayload, |
| 19 | 23 | CreateSecretResult, |
| @@ -36,7 +40,10 @@ import { · 16 unmodified lines | ||
| 36 | 40 | listLocalSecrets, |
| 37 | 41 | updateLocalSecret, |
| 38 | 42 | } from "./local/secrets"; |
| 39 | −import type { CreatePolicyPayload, UpdatePolicyPayload } from "./policies/contracts"; | |
| 43 | +import type { | |
| 44 | + CreatePolicyPayload, | |
| 45 | + UpdatePolicyPayload, | |
| 46 | +} from "./policies/contracts"; | |
| 40 | 47 | import { |
| 41 | 48 | createPolicy, |
| 42 | 49 | getPolicy, |
| @@ -46,10 +53,12 @@ import { · 3 unmodified lines | ||
| 46 | 53 | } from "./policies/operations"; |
| 47 | 54 | import type { |
| 48 | 55 | CreateSourcePayload, |
| 49 | − CreateWorkspaceOauthClientPayload, | |
| 56 | + CreateScopeOauthClientPayload, | |
| 50 | 57 | UpdateSourcePayload, |
| 51 | 58 | } from "./sources/contracts"; |
| 52 | −import { discoverSource } from "./sources/discovery"; | |
| 59 | +import { | |
| 60 | + discoverSource, | |
| 61 | +} from "./sources/discovery"; | |
| 53 | 62 | import { |
| 54 | 63 | discoverSourceInspectionTools, |
| 55 | 64 | getSourceInspection, |
| @@ -62,17 +71,23 @@ import { · 6 unmodified lines | ||
| 62 | 71 | removeSource, |
| 63 | 72 | updateSource, |
| 64 | 73 | } from "./sources/operations"; |
| 65 | −import type { ExecutorBackend } from "./backend"; | |
| 74 | +import type { | |
| 75 | + ExecutorBackend, | |
| 76 | +} from "./backend"; | |
| 66 | 77 | import { |
| 67 | 78 | provideExecutorRuntime, |
| 68 | 79 | type ExecutorRuntime, |
| 69 | 80 | type ExecutorRuntimeOptions, |
| 70 | − type CreateWorkspaceInternalToolMap, | |
| 81 | + type CreateScopeInternalToolMap, | |
| 71 | 82 | type ResolveExecutionEnvironment, |
| 72 | 83 | type ResolveSecretMaterial, |
| 73 | 84 | RuntimeSourceAuthServiceTag, |
| 74 | 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 | 91 | import type { |
| 77 | 92 | CompleteProviderOauthCallbackResult, |
| 78 | 93 | CompleteSourceCredentialSetupResult, |
| @@ -96,29 +111,30 @@ type ProvidedEffect<T extends Effect.Effect<any, any, any>> = Effect.Effect< · 17 unmodified lines | ||
| 96 | 111 | |
| 97 | 112 | export type ExecutorSourceInput = DistributiveOmit< |
| 98 | 113 | ExecutorAddSourceInput, |
| 99 | − "workspaceId" | "actorAccountId" | "executionId" | "interactionId" | |
| 114 | + "scopeId" | "actorScopeId" | "executionId" | "interactionId" | |
| 100 | 115 | >; |
| 101 | 116 | |
| 102 | 117 | export type ExecutorSourceBatchInput = DistributiveOmit< |
| 103 | 118 | ConnectGoogleDiscoveryBatchInput, |
| 104 | − "workspaceId" | "actorAccountId" | "executionId" | "interactionId" | |
| 119 | + "scopeId" | "actorScopeId" | "executionId" | "interactionId" | |
| 105 | 120 | >; |
| 106 | 121 | |
| 107 | 122 | export type ExecutorMcpSourceInput = DistributiveOmit< |
| 108 | 123 | ConnectMcpSourceInput, |
| 109 | − "workspaceId" | "actorAccountId" | |
| 124 | + "scopeId" | "actorScopeId" | |
| 110 | 125 | >; |
| 111 | 126 | |
| 112 | 127 | export type ExecutorSourceOAuthInput = DistributiveOmit< |
| 113 | 128 | StartSourceOAuthSessionInput, |
| 114 | − "workspaceId" | "actorAccountId" | |
| 129 | + "scopeId" | "actorScopeId" | |
| 115 | 130 | >; |
| 116 | 131 | |
| 117 | 132 | export type Executor = { |
| 118 | 133 | runtime: ExecutorRuntime; |
| 119 | 134 | installation: LocalInstallation; |
| 120 | − workspaceId: WorkspaceId; | |
| 121 | − accountId: AccountId; | |
| 135 | + scopeId: ScopeId; | |
| 136 | + actorScopeId: ScopeId; | |
| 137 | + resolutionScopeIds: ReadonlyArray<ScopeId>; | |
| 122 | 138 | provide: <A, E, R>(effect: Effect.Effect<A, E, R>) => Effect.Effect<A, E, any>; |
| 123 | 139 | run: <A, E, R>(effect: Effect.Effect<A, E, R>) => Promise<A>; |
| 124 | 140 | close: () => Promise<void>; |
| @@ -202,12 +218,12 @@ export type Executor = { · 77 unmodified lines | ||
| 202 | 218 | oauthClients: { |
| 203 | 219 | list: ( |
| 204 | 220 | providerKey: string, |
| 205 | − ) => Effect.Effect<ReadonlyArray<WorkspaceOauthClient>, Error, never>; | |
| 221 | + ) => Effect.Effect<ReadonlyArray<ScopeOauthClient>, Error, never>; | |
| 206 | 222 | create: ( |
| 207 | − payload: CreateWorkspaceOauthClientPayload, | |
| 208 | − ) => Effect.Effect<WorkspaceOauthClient, Error, never>; | |
| 223 | + payload: CreateScopeOauthClientPayload, | |
| 224 | + ) => Effect.Effect<ScopeOauthClient, Error, never>; | |
| 209 | 225 | remove: ( |
| 210 | − oauthClientId: WorkspaceOauthClient["id"], | |
| 226 | + oauthClientId: ScopeOauthClient["id"], | |
| 211 | 227 | ) => Effect.Effect<boolean, Error, never>; |
| 212 | 228 | }; |
| 213 | 229 | providerGrants: { |
| @@ -225,8 +241,8 @@ export type Executor = { · 11 unmodified lines | ||
| 225 | 241 | errorDescription?: string | null; |
| 226 | 242 | }) => Effect.Effect<CompleteSourceOAuthSessionResult, Error, never>; |
| 227 | 243 | completeProviderCallback: (input: { |
| 228 | − workspaceId?: WorkspaceId; | |
| 229 | − actorAccountId?: AccountId | null; | |
| 244 | + scopeId?: ScopeId; | |
| 245 | + actorScopeId?: ScopeId | null; | |
| 230 | 246 | state: string; |
| 231 | 247 | code?: string | null; |
| 232 | 248 | error?: string | null; |
| @@ -275,13 +291,13 @@ export type Executor = { · 42 unmodified lines | ||
| 275 | 291 | remove: (secretId: string) => Promise<DeleteSecretResult>; |
| 276 | 292 | }; |
| 277 | 293 | policies: { |
| 278 | − list: () => Promise<ReadonlyArray<LocalWorkspacePolicy>>; | |
| 279 | − create: (payload: CreatePolicyPayload) => Promise<LocalWorkspacePolicy>; | |
| 280 | − get: (policyId: string) => Promise<LocalWorkspacePolicy>; | |
| 294 | + list: () => Promise<ReadonlyArray<LocalScopePolicy>>; | |
| 295 | + create: (payload: CreatePolicyPayload) => Promise<LocalScopePolicy>; | |
| 296 | + get: (policyId: string) => Promise<LocalScopePolicy>; | |
| 281 | 297 | update: ( |
| 282 | 298 | policyId: string, |
| 283 | 299 | payload: UpdatePolicyPayload, |
| 284 | − ) => Promise<LocalWorkspacePolicy>; | |
| 300 | + ) => Promise<LocalScopePolicy>; | |
| 285 | 301 | remove: (policyId: string) => Promise<boolean>; |
| 286 | 302 | }; |
| 287 | 303 | sources: { |
| @@ -314,11 +330,11 @@ export type Executor = { · 26 unmodified lines | ||
| 314 | 330 | }) => Promise<Effect.Effect.Success<ReturnType<typeof discoverSourceInspectionTools>>>; |
| 315 | 331 | }; |
| 316 | 332 | oauthClients: { |
| 317 | − list: (providerKey: string) => Promise<ReadonlyArray<WorkspaceOauthClient>>; | |
| 333 | + list: (providerKey: string) => Promise<ReadonlyArray<ScopeOauthClient>>; | |
| 318 | 334 | create: ( |
| 319 | − payload: CreateWorkspaceOauthClientPayload, | |
| 320 | − ) => Promise<WorkspaceOauthClient>; | |
| 321 | − remove: (oauthClientId: WorkspaceOauthClient["id"]) => Promise<boolean>; | |
| 335 | + payload: CreateScopeOauthClientPayload, | |
| 336 | + ) => Promise<ScopeOauthClient>; | |
| 337 | + remove: (oauthClientId: ScopeOauthClient["id"]) => Promise<boolean>; | |
| 322 | 338 | }; |
| 323 | 339 | providerGrants: { |
| 324 | 340 | remove: (grantId: ProviderAuthGrant["id"]) => Promise<boolean>; |
| @@ -333,8 +349,8 @@ export type Executor = { · 8 unmodified lines | ||
| 333 | 349 | errorDescription?: string | null; |
| 334 | 350 | }) => Promise<CompleteSourceOAuthSessionResult>; |
| 335 | 351 | completeProviderCallback: (input: { |
| 336 | − workspaceId?: WorkspaceId; | |
| 337 | − actorAccountId?: AccountId | null; | |
| 352 | + scopeId?: ScopeId; | |
| 353 | + actorScopeId?: ScopeId | null; | |
| 338 | 354 | state: string; |
| 339 | 355 | code?: string | null; |
| 340 | 356 | error?: string | null; |
| @@ -357,8 +373,8 @@ export type CreateExecutorOptions = ExecutorRuntimeOptions & { · 16 unmodified lines | ||
| 357 | 373 | |
| 358 | 374 | const fromRuntime = (runtime: ExecutorRuntime): Executor => { |
| 359 | 375 | const installation = runtime.localInstallation; |
| 360 | − const workspaceId = installation.workspaceId; | |
| 361 | − const accountId = installation.accountId; | |
| 376 | + const scopeId = installation.scopeId; | |
| 377 | + const actorScopeId = installation.actorScopeId; | |
| 362 | 378 | const provide = <A, E, R>(effect: Effect.Effect<A, E, R>) => |
| 363 | 379 | provideExecutorRuntime(effect, runtime); |
| 364 | 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 | 399 | get: ({ sourceId, interactionId }) => |
| 384 | 400 | provide( |
| 385 | 401 | getSourceCredentialInteraction({ |
| 386 | − workspaceId, | |
| 402 | + scopeId, | |
| 387 | 403 | sourceId, |
| 388 | 404 | interactionId, |
| 389 | 405 | }), |
| @@ -391,7 +407,7 @@ const fromRuntime = (runtime: ExecutorRuntime): Executor => { · 1 unmodified line | ||
| 391 | 407 | submit: ({ sourceId, interactionId, action, token }) => |
| 392 | 408 | provide( |
| 393 | 409 | submitSourceCredentialInteraction({ |
| 394 | − workspaceId, | |
| 410 | + scopeId, | |
| 395 | 411 | sourceId, |
| 396 | 412 | interactionId, |
| 397 | 413 | action, |
| @@ -401,7 +417,7 @@ const fromRuntime = (runtime: ExecutorRuntime): Executor => { · 3 unmodified lines | ||
| 401 | 417 | complete: ({ sourceId, state, code, error, errorDescription }) => |
| 402 | 418 | provide( |
| 403 | 419 | completeSourceCredentialSetup({ |
| 404 | − workspaceId, | |
| 420 | + scopeId, | |
| 405 | 421 | sourceId, |
| 406 | 422 | state, |
| 407 | 423 | code, |
| @@ -419,15 +435,15 @@ const fromRuntime = (runtime: ExecutorRuntime): Executor => { · 11 unmodified lines | ||
| 419 | 435 | remove: (secretId: string) => provide(deleteLocalSecret(secretId)), |
| 420 | 436 | }, |
| 421 | 437 | policies: { |
| 422 | − list: () => provide(listPolicies(workspaceId)), | |
| 438 | + list: () => provide(listPolicies(scopeId)), | |
| 423 | 439 | create: (payload: CreatePolicyPayload) => |
| 424 | − provide(createPolicy({ workspaceId, payload })), | |
| 440 | + provide(createPolicy({ scopeId, payload })), | |
| 425 | 441 | get: (policyId: string) => |
| 426 | − provide(getPolicy({ workspaceId, policyId: policyId as never })), | |
| 442 | + provide(getPolicy({ scopeId, policyId: policyId as never })), | |
| 427 | 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 | 445 | remove: (policyId: string) => |
| 430 | − provide(removePolicy({ workspaceId, policyId: policyId as never })), | |
| 446 | + provide(removePolicy({ scopeId, policyId: policyId as never })), | |
| 431 | 447 | }, |
| 432 | 448 | sources: { |
| 433 | 449 | add: (input: ExecutorSourceInput, options?: { baseUrl?: string | null }) => |
| @@ -436,8 +452,8 @@ const fromRuntime = (runtime: ExecutorRuntime): Executor => { · 2 unmodified lines | ||
| 436 | 452 | return service.addExecutorSource( |
| 437 | 453 | { |
| 438 | 454 | ...input, |
| 439 | − workspaceId, | |
| 440 | − actorAccountId: accountId, | |
| 455 | + scopeId, | |
| 456 | + actorScopeId: actorScopeId, | |
| 441 | 457 | executionId: session.executionId, |
| 442 | 458 | interactionId: session.interactionId, |
| 443 | 459 | }, |
| @@ -448,8 +464,8 @@ const fromRuntime = (runtime: ExecutorRuntime): Executor => { · 4 unmodified lines | ||
| 448 | 464 | provideSourceAuth((service) => |
| 449 | 465 | service.connectMcpSource({ |
| 450 | 466 | ...payload, |
| 451 | − workspaceId, | |
| 452 | − actorAccountId: accountId, | |
| 467 | + scopeId, | |
| 468 | + actorScopeId: actorScopeId, | |
| 453 | 469 | }), |
| 454 | 470 | ), |
| 455 | 471 | connectBatch: (payload: ExecutorSourceBatchInput) => |
| @@ -457,8 +473,8 @@ const fromRuntime = (runtime: ExecutorRuntime): Executor => { · 1 unmodified line | ||
| 457 | 473 | const session = createSdkSourceSession(); |
| 458 | 474 | return service.connectGoogleDiscoveryBatch({ |
| 459 | 475 | ...payload, |
| 460 | − workspaceId, | |
| 461 | − actorAccountId: accountId, | |
| 476 | + scopeId, | |
| 477 | + actorScopeId: actorScopeId, | |
| 462 | 478 | executionId: session.executionId, |
| 463 | 479 | interactionId: session.interactionId, |
| 464 | 480 | }); |
| @@ -467,22 +483,22 @@ const fromRuntime = (runtime: ExecutorRuntime): Executor => { · 2 unmodified lines | ||
| 467 | 483 | url: string; |
| 468 | 484 | probeAuth?: Parameters<typeof discoverSource>[0]["probeAuth"]; |
| 469 | 485 | }) => provide(discoverSource(input)), |
| 470 | − list: () => provide(listSources({ workspaceId, accountId })), | |
| 486 | + list: () => provide(listSources({ scopeId, actorScopeId })), | |
| 471 | 487 | create: (payload: CreateSourcePayload) => |
| 472 | − provide(createSource({ workspaceId, accountId, payload })), | |
| 488 | + provide(createSource({ scopeId, actorScopeId, payload })), | |
| 473 | 489 | get: (sourceId: Source["id"]) => |
| 474 | − provide(getSource({ workspaceId, sourceId, accountId })), | |
| 490 | + provide(getSource({ scopeId, sourceId, actorScopeId })), | |
| 475 | 491 | update: (sourceId: Source["id"], payload: UpdateSourcePayload) => |
| 476 | − provide(updateSource({ workspaceId, sourceId, accountId, payload })), | |
| 492 | + provide(updateSource({ scopeId, sourceId, actorScopeId, payload })), | |
| 477 | 493 | remove: (sourceId: Source["id"]) => |
| 478 | − provide(removeSource({ workspaceId, sourceId })), | |
| 494 | + provide(removeSource({ scopeId, sourceId })), | |
| 479 | 495 | inspection: { |
| 480 | 496 | get: (sourceId: Source["id"]) => |
| 481 | − provide(getSourceInspection({ workspaceId, sourceId })), | |
| 497 | + provide(getSourceInspection({ scopeId, sourceId })), | |
| 482 | 498 | tool: ({ sourceId, toolPath }: { sourceId: Source["id"]; toolPath: string }) => |
| 483 | 499 | provide( |
| 484 | 500 | getSourceInspectionToolDetail({ |
| 485 | − workspaceId, | |
| 501 | + scopeId, | |
| 486 | 502 | sourceId, |
| 487 | 503 | toolPath, |
| 488 | 504 | }), |
| @@ -496,7 +512,7 @@ const fromRuntime = (runtime: ExecutorRuntime): Executor => { · 7 unmodified lines | ||
| 496 | 512 | }) => |
| 497 | 513 | provide( |
| 498 | 514 | discoverSourceInspectionTools({ |
| 499 | − workspaceId, | |
| 515 | + scopeId, | |
| 500 | 516 | sourceId, |
| 501 | 517 | payload, |
| 502 | 518 | }), |
| @@ -505,24 +521,24 @@ const fromRuntime = (runtime: ExecutorRuntime): Executor => { · 2 unmodified lines | ||
| 505 | 521 | oauthClients: { |
| 506 | 522 | list: (providerKey: string) => |
| 507 | 523 | provideSourceAuth((service) => |
| 508 | − service.listWorkspaceOauthClients({ | |
| 509 | − workspaceId, | |
| 524 | + service.listScopeOauthClients({ | |
| 525 | + scopeId, | |
| 510 | 526 | providerKey, |
| 511 | 527 | }), |
| 512 | 528 | ), |
| 513 | − create: (payload: CreateWorkspaceOauthClientPayload) => | |
| 529 | + create: (payload: CreateScopeOauthClientPayload) => | |
| 514 | 530 | provideSourceAuth((service) => |
| 515 | − service.createWorkspaceOauthClient({ | |
| 516 | − workspaceId, | |
| 531 | + service.createScopeOauthClient({ | |
| 532 | + scopeId, | |
| 517 | 533 | providerKey: payload.providerKey, |
| 518 | 534 | label: payload.label, |
| 519 | 535 | oauthClient: payload.oauthClient, |
| 520 | 536 | }), |
| 521 | 537 | ), |
| 522 | − remove: (oauthClientId: WorkspaceOauthClient["id"]) => | |
| 538 | + remove: (oauthClientId: ScopeOauthClient["id"]) => | |
| 523 | 539 | provideSourceAuth((service) => |
| 524 | − service.removeWorkspaceOauthClient({ | |
| 525 | − workspaceId, | |
| 540 | + service.removeScopeOauthClient({ | |
| 541 | + scopeId, | |
| 526 | 542 | oauthClientId, |
| 527 | 543 | }), |
| 528 | 544 | ), |
| @@ -531,7 +547,7 @@ const fromRuntime = (runtime: ExecutorRuntime): Executor => { · 2 unmodified lines | ||
| 531 | 547 | remove: (grantId: ProviderAuthGrant["id"]) => |
| 532 | 548 | provideSourceAuth((service) => |
| 533 | 549 | service.removeProviderAuthGrant({ |
| 534 | − workspaceId, | |
| 550 | + scopeId, | |
| 535 | 551 | grantId, |
| 536 | 552 | }), |
| 537 | 553 | ), |
| @@ -542,8 +558,8 @@ const fromRuntime = (runtime: ExecutorRuntime): Executor => { · 4 unmodified lines | ||
| 542 | 558 | provideSourceAuth((service) => |
| 543 | 559 | service.startSourceOAuthSession({ |
| 544 | 560 | ...input, |
| 545 | − workspaceId, | |
| 546 | − actorAccountId: accountId, | |
| 561 | + scopeId, | |
| 562 | + actorScopeId: actorScopeId, | |
| 547 | 563 | }), |
| 548 | 564 | ), |
| 549 | 565 | completeSourceAuth: ({ state, code, error, errorDescription }) => |
| @@ -559,8 +575,8 @@ const fromRuntime = (runtime: ExecutorRuntime): Executor => { · 9 unmodified lines | ||
| 559 | 575 | provideSourceAuth((service) => |
| 560 | 576 | service.completeProviderOauthCallback({ |
| 561 | 577 | ...input, |
| 562 | − workspaceId: input.workspaceId ?? workspaceId, | |
| 563 | − actorAccountId: input.actorAccountId ?? accountId, | |
| 578 | + scopeId: input.scopeId ?? scopeId, | |
| 579 | + actorScopeId: input.actorScopeId ?? actorScopeId, | |
| 564 | 580 | }), |
| 565 | 581 | ), |
| 566 | 582 | }, |
| @@ -568,20 +584,20 @@ const fromRuntime = (runtime: ExecutorRuntime): Executor => { · 1 unmodified line | ||
| 568 | 584 | create: (payload: CreateExecutionPayload) => |
| 569 | 585 | provide( |
| 570 | 586 | createExecution({ |
| 571 | − workspaceId, | |
| 587 | + scopeId, | |
| 572 | 588 | payload, |
| 573 | − createdByAccountId: accountId, | |
| 589 | + createdByScopeId: actorScopeId, | |
| 574 | 590 | }), |
| 575 | 591 | ), |
| 576 | 592 | get: (executionId: Execution["id"]) => |
| 577 | − provide(getExecution({ workspaceId, executionId })), | |
| 593 | + provide(getExecution({ scopeId, executionId })), | |
| 578 | 594 | resume: (executionId: Execution["id"], payload: ResumeExecutionPayload) => |
| 579 | 595 | provide( |
| 580 | 596 | resumeExecution({ |
| 581 | − workspaceId, | |
| 597 | + scopeId, | |
| 582 | 598 | executionId, |
| 583 | 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 | 606 | return { |
| 591 | 607 | runtime, |
| 592 | 608 | installation, |
| 593 | − workspaceId, | |
| 594 | − accountId, | |
| 609 | + scopeId, | |
| 610 | + actorScopeId, | |
| 611 | + resolutionScopeIds: installation.resolutionScopeIds, | |
| 595 | 612 | provide, |
| 596 | 613 | run, |
| 597 | 614 | close: () => runtime.close(), |
| @@ -1,4 +1,6 @@ | ||
| 1 | −import { SecretMaterialPurposeSchema } from "../schema"; | |
| 1 | +import { | |
| 2 | + SecretMaterialPurposeSchema, | |
| 3 | +} from "../schema"; | |
| 2 | 4 | import * as Schema from "effect/Schema"; |
| 3 | 5 | |
| 4 | 6 | export const SecretProviderSchema = Schema.Struct({ |
| @@ -2,25 +2,37 @@ import type { · 1 unmodified line | ||
| 2 | 2 | Execution, |
| 3 | 3 | ExecutionInteraction, |
| 4 | 4 | Source, |
| 5 | − WorkspaceId, | |
| 5 | + ScopeId, | |
| 6 | 6 | } from "../schema"; |
| 7 | 7 | import { |
| 8 | 8 | SourceIdSchema, |
| 9 | − WorkspaceIdSchema, | |
| 9 | + ScopeIdSchema, | |
| 10 | 10 | } from "../schema"; |
| 11 | 11 | import * as Effect from "effect/Effect"; |
| 12 | 12 | import * as Option from "effect/Option"; |
| 13 | 13 | |
| 14 | −import { submitExecutionInteractionResponse } from "../runtime/execution/service"; | |
| 15 | −import { LiveExecutionManagerService } from "../runtime/execution/live"; | |
| 16 | −import { operationErrors } from "../runtime/policy/operation-errors"; | |
| 17 | −import { InstallationStore } from "../runtime/workspace/storage"; | |
| 18 | −import { RuntimeSourceAuthServiceTag } from "../runtime/sources/source-auth-service"; | |
| 14 | +import { | |
| 15 | + submitExecutionInteractionResponse, | |
| 16 | +} from "../runtime/execution/service"; | |
| 17 | +import { | |
| 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 | 29 | import { |
| 20 | 30 | createSourceCredentialSelectionBearerContent, |
| 21 | 31 | createSourceCredentialSelectionNoneContent, |
| 22 | 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 | 37 | const localOps = { |
| 26 | 38 | installation: operationErrors("local.installation.get"), |
| @@ -34,7 +46,7 @@ type SourceCredentialInteraction = { · 7 unmodified lines | ||
| 34 | 46 | executionId: Execution["id"]; |
| 35 | 47 | status: ExecutionInteraction["status"]; |
| 36 | 48 | message: string; |
| 37 | − workspaceId: WorkspaceId; | |
| 49 | + scopeId: ScopeId; | |
| 38 | 50 | sourceId: Source["id"]; |
| 39 | 51 | sourceLabel: string; |
| 40 | 52 | endpoint: string; |
| @@ -100,10 +112,10 @@ export const decodeSourceCredentialInteraction = ( · 59 unmodified lines | ||
| 100 | 112 | return null; |
| 101 | 113 | } |
| 102 | 114 | |
| 103 | − const workspaceId = trimOrNull(asString(args.workspaceId)); | |
| 115 | + const scopeId = trimOrNull(asString(args.scopeId)); | |
| 104 | 116 | const sourceId = trimOrNull(asString(args.sourceId)); |
| 105 | 117 | const message = trimOrNull(asString(elicitation.message)); |
| 106 | − if (workspaceId === null || sourceId === null || message === null) { | |
| 118 | + if (scopeId === null || sourceId === null || message === null) { | |
| 107 | 119 | return null; |
| 108 | 120 | } |
| 109 | 121 | |
| @@ -112,7 +124,7 @@ export const decodeSourceCredentialInteraction = ( · 2 unmodified lines | ||
| 112 | 124 | executionId: interaction.executionId, |
| 113 | 125 | status: interaction.status, |
| 114 | 126 | message, |
| 115 | − workspaceId: WorkspaceIdSchema.make(workspaceId), | |
| 127 | + scopeId: ScopeIdSchema.make(scopeId), | |
| 116 | 128 | sourceId: SourceIdSchema.make(sourceId), |
| 117 | 129 | }; |
| 118 | 130 | } catch { |
| @@ -121,7 +133,7 @@ export const decodeSourceCredentialInteraction = ( · 2 unmodified lines | ||
| 121 | 133 | }; |
| 122 | 134 | |
| 123 | 135 | const loadSourceCredentialInteraction = (input: { |
| 124 | − workspaceId: WorkspaceId; | |
| 136 | + scopeId: ScopeId; | |
| 125 | 137 | sourceId: Source["id"]; |
| 126 | 138 | interactionId: ExecutionInteraction["id"]; |
| 127 | 139 | operation: |
| @@ -153,18 +165,18 @@ const loadSourceCredentialInteraction = (input: { · 25 unmodified lines | ||
| 153 | 165 | const decoded = decodeSourceCredentialInteraction(stored.value); |
| 154 | 166 | if ( |
| 155 | 167 | decoded === null || |
| 156 | − decoded.workspaceId !== input.workspaceId || | |
| 168 | + decoded.scopeId !== input.scopeId || | |
| 157 | 169 | decoded.sourceId !== input.sourceId |
| 158 | 170 | ) { |
| 159 | 171 | return yield* input.operation.notFound( |
| 160 | 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 | 177 | const source = yield* sourceAuthService |
| 166 | 178 | .getSourceById({ |
| 167 | − workspaceId: input.workspaceId, | |
| 179 | + scopeId: input.scopeId, | |
| 168 | 180 | sourceId: input.sourceId, |
| 169 | 181 | }) |
| 170 | 182 | .pipe( |
| @@ -197,7 +209,7 @@ export const getLocalInstallation = () => · 26 unmodified lines | ||
| 197 | 209 | }); |
| 198 | 210 | |
| 199 | 211 | export const getSourceCredentialInteraction = (input: { |
| 200 | − workspaceId: WorkspaceId; | |
| 212 | + scopeId: ScopeId; | |
| 201 | 213 | sourceId: Source["id"]; |
| 202 | 214 | interactionId: ExecutionInteraction["id"]; |
| 203 | 215 | }) => |
| @@ -207,7 +219,7 @@ export const getSourceCredentialInteraction = (input: { · 3 unmodified lines | ||
| 207 | 219 | }); |
| 208 | 220 | |
| 209 | 221 | export const submitSourceCredentialInteraction = (input: { |
| 210 | − workspaceId: WorkspaceId; | |
| 222 | + scopeId: ScopeId; | |
| 211 | 223 | sourceId: Source["id"]; |
| 212 | 224 | interactionId: ExecutionInteraction["id"]; |
| 213 | 225 | action: "submit" | "continue" | "cancel"; |
| @@ -215,7 +227,7 @@ export const submitSourceCredentialInteraction = (input: { · 1 unmodified line | ||
| 215 | 227 | }) => |
| 216 | 228 | Effect.gen(function* () { |
| 217 | 229 | const interaction = yield* loadSourceCredentialInteraction({ |
| 218 | − workspaceId: input.workspaceId, | |
| 230 | + scopeId: input.scopeId, | |
| 219 | 231 | sourceId: input.sourceId, |
| 220 | 232 | interactionId: input.interactionId, |
| 221 | 233 | operation: localOps.sourceCredentialSubmit, |
| @@ -370,7 +382,7 @@ export const submitSourceCredentialInteraction = (input: { · 148 unmodified lines | ||
| 370 | 382 | }); |
| 371 | 383 | |
| 372 | 384 | export const completeSourceCredentialSetup = (input: { |
| 373 | − workspaceId: WorkspaceId; | |
| 385 | + scopeId: ScopeId; | |
| 374 | 386 | sourceId: Source["id"]; |
| 375 | 387 | state: string; |
| 376 | 388 | code?: string | null; |
| @@ -1,7 +1,9 @@ | ||
| 1 | 1 | import * as Effect from "effect/Effect"; |
| 2 | 2 | import * as Option from "effect/Option"; |
| 3 | 3 | |
| 4 | −import { SecretMaterialIdSchema } from "../schema"; | |
| 4 | +import { | |
| 5 | + SecretMaterialIdSchema, | |
| 6 | +} from "../schema"; | |
| 5 | 7 | import { |
| 6 | 8 | type CreateSecretPayload, |
| 7 | 9 | type CreateSecretResult, |
| @@ -16,15 +18,21 @@ import { · 8 unmodified lines | ||
| 16 | 18 | ControlPlaneNotFoundError, |
| 17 | 19 | ControlPlaneStorageError, |
| 18 | 20 | } from "../errors"; |
| 19 | −import { requireRuntimeLocalWorkspace } from "../runtime/workspace/runtime-context"; | |
| 21 | +import { | |
| 22 | + requireRuntimeLocalScope, | |
| 23 | +} from "../runtime/scope/runtime-context"; | |
| 20 | 24 | import { |
| 21 | 25 | LocalInstanceConfigService, |
| 22 | 26 | SecretMaterialDeleterService, |
| 23 | 27 | SecretMaterialStorerService, |
| 24 | 28 | SecretMaterialUpdaterService, |
| 25 | −} from "../runtime/workspace/secret-material-providers"; | |
| 26 | −import { RuntimeSourceStoreService } from "../runtime/sources/source-store"; | |
| 27 | −import { ExecutorStateStore } from "../runtime/executor-state-store"; | |
| 29 | +} from "../runtime/scope/secret-material-providers"; | |
| 30 | +import { | |
| 31 | + RuntimeSourceStoreService, | |
| 32 | +} from "../runtime/sources/source-store"; | |
| 33 | +import { | |
| 34 | + ExecutorStateStore, | |
| 35 | +} from "../runtime/executor-state-store"; | |
| 28 | 36 | |
| 29 | 37 | const secretStorageError = (operation: string, message: string) => |
| 30 | 38 | new ControlPlaneStorageError({ |
| @@ -40,9 +48,9 @@ export const listLocalSecrets = () => · 9 unmodified lines | ||
| 40 | 48 | Effect.gen(function* () { |
| 41 | 49 | const store = yield* ExecutorStateStore; |
| 42 | 50 | const sourceStore = yield* RuntimeSourceStoreService; |
| 43 | − const runtimeLocalWorkspace = yield* requireRuntimeLocalWorkspace().pipe( | |
| 51 | + const runtimeLocalScope = yield* requireRuntimeLocalScope().pipe( | |
| 44 | 52 | Effect.mapError(() => |
| 45 | − secretStorageError("secrets.list", "Failed resolving local workspace."), | |
| 53 | + secretStorageError("secrets.list", "Failed resolving local scope."), | |
| 46 | 54 | ), |
| 47 | 55 | ); |
| 48 | 56 | const secretMaterials = yield* store.secretMaterials |
| @@ -53,10 +61,10 @@ export const listLocalSecrets = () => · 4 unmodified lines | ||
| 53 | 61 | ), |
| 54 | 62 | ); |
| 55 | 63 | const linkedSourcesMap = yield* sourceStore |
| 56 | − .listLinkedSecretSourcesInWorkspace( | |
| 57 | − runtimeLocalWorkspace.installation.workspaceId, | |
| 64 | + .listLinkedSecretSourcesInScope( | |
| 65 | + runtimeLocalScope.installation.scopeId, | |
| 58 | 66 | { |
| 59 | − actorAccountId: runtimeLocalWorkspace.installation.accountId, | |
| 67 | + actorScopeId: runtimeLocalScope.installation.actorScopeId, | |
| 60 | 68 | }, |
| 61 | 69 | ) |
| 62 | 70 | .pipe( |
| @@ -1,23 +1,25 @@ | ||
| 1 | 1 | import { |
| 2 | − LocalWorkspacePolicyApprovalModeSchema, | |
| 3 | − LocalWorkspacePolicyEffectSchema, | |
| 2 | + LocalScopePolicyApprovalModeSchema, | |
| 3 | + LocalScopePolicyEffectSchema, | |
| 4 | 4 | } from "../schema"; |
| 5 | 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 | 12 | resourcePattern: OptionalTrimmedNonEmptyStringSchema, |
| 11 | − effect: Schema.optional(LocalWorkspacePolicyEffectSchema), | |
| 12 | − approvalMode: Schema.optional(LocalWorkspacePolicyApprovalModeSchema), | |
| 13 | + effect: Schema.optional(LocalScopePolicyEffectSchema), | |
| 14 | + approvalMode: Schema.optional(LocalScopePolicyApprovalModeSchema), | |
| 13 | 15 | priority: Schema.optional(Schema.Number), |
| 14 | 16 | enabled: Schema.optional(Schema.Boolean), |
| 15 | 17 | }); |
| 16 | 18 | |
| 17 | −export const CreatePolicyPayloadSchema = LocalWorkspacePolicyPayloadSchema; | |
| 19 | +export const CreatePolicyPayloadSchema = LocalScopePolicyPayloadSchema; | |
| 18 | 20 | |
| 19 | 21 | export type CreatePolicyPayload = typeof CreatePolicyPayloadSchema.Type; |
| 20 | 22 | |
| 21 | −export const UpdatePolicyPayloadSchema = LocalWorkspacePolicyPayloadSchema; | |
| 23 | +export const UpdatePolicyPayloadSchema = LocalScopePolicyPayloadSchema; | |
| 22 | 24 | |
| 23 | 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 | 5 | import type { |
| 4 | 6 | CreatePolicyPayload, |
| @@ -7,23 +9,29 @@ import type { · 2 unmodified lines | ||
| 7 | 9 | import { |
| 8 | 10 | PolicyIdSchema, |
| 9 | 11 | type LocalExecutorConfig, |
| 10 | − type LocalWorkspacePolicy, | |
| 12 | + type LocalScopePolicy, | |
| 11 | 13 | type PolicyId, |
| 12 | − type WorkspaceId, | |
| 14 | + type ScopeId, | |
| 13 | 15 | } from "../schema"; |
| 14 | 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 | 21 | import type { |
| 18 | − WorkspaceConfigStoreShape, | |
| 19 | − WorkspaceStateStoreShape, | |
| 20 | −} from "../runtime/workspace/storage"; | |
| 22 | + ScopeConfigStoreShape, | |
| 23 | + ScopeStateStoreShape, | |
| 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 | 32 | import { |
| 22 | − WorkspaceConfigStore, | |
| 23 | − WorkspaceStateStore, | |
| 24 | −} from "../runtime/workspace/storage"; | |
| 25 | −import { type LocalWorkspaceState } from "../runtime/workspace-state"; | |
| 26 | −import { derivePolicyConfigKey } from "../runtime/workspace/workspace-sync"; | |
| 33 | + derivePolicyConfigKey, | |
| 34 | +} from "../runtime/scope/scope-sync"; | |
| 27 | 35 | import { |
| 28 | 36 | type OperationErrors, |
| 29 | 37 | operationErrors, |
| @@ -39,34 +47,34 @@ const policyOps = { · 9 unmodified lines | ||
| 39 | 47 | |
| 40 | 48 | const cloneJson = <T>(value: T): T => JSON.parse(JSON.stringify(value)) as T; |
| 41 | 49 | |
| 42 | −const workspacePolicyStableKey = (input: { | |
| 43 | − workspaceId: WorkspaceId; | |
| 44 | − workspaceRoot?: string | null; | |
| 45 | −}): string => input.workspaceRoot?.trim() || input.workspaceId; | |
| 50 | +const scopePolicyStableKey = (input: { | |
| 51 | + scopeId: ScopeId; | |
| 52 | + scopeRoot?: string | null; | |
| 53 | +}): string => input.scopeRoot?.trim() || input.scopeId; | |
| 46 | 54 | |
| 47 | 55 | const localPolicyIdForKey = (input: { |
| 48 | − workspaceStableKey: string; | |
| 56 | + scopeStableKey: string; | |
| 49 | 57 | key: string; |
| 50 | 58 | }): PolicyId => |
| 51 | 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: { | |
| 56 | − workspaceId: WorkspaceId; | |
| 57 | − workspaceStableKey: string; | |
| 63 | +const toLocalScopePolicy = (input: { | |
| 64 | + scopeId: ScopeId; | |
| 65 | + scopeStableKey: string; | |
| 58 | 66 | key: string; |
| 59 | 67 | policyConfig: NonNullable<LocalExecutorConfig["policies"]>[string]; |
| 60 | − state: LocalWorkspaceState["policies"][string] | undefined; | |
| 61 | −}): LocalWorkspacePolicy => ({ | |
| 68 | + state: LocalScopeState["policies"][string] | undefined; | |
| 69 | +}): LocalScopePolicy => ({ | |
| 62 | 70 | id: |
| 63 | 71 | input.state?.id ?? |
| 64 | 72 | localPolicyIdForKey({ |
| 65 | − workspaceStableKey: input.workspaceStableKey, | |
| 73 | + scopeStableKey: input.scopeStableKey, | |
| 66 | 74 | key: input.key, |
| 67 | 75 | }), |
| 68 | 76 | key: input.key, |
| 69 | − workspaceId: input.workspaceId, | |
| 77 | + scopeId: input.scopeId, | |
| 70 | 78 | resourcePattern: input.policyConfig.match.trim(), |
| 71 | 79 | effect: input.policyConfig.action, |
| 72 | 80 | approvalMode: input.policyConfig.approval === "manual" ? "required" : "auto", |
| @@ -76,51 +84,51 @@ const toLocalWorkspacePolicy = (input: { · 3 unmodified lines | ||
| 76 | 84 | updatedAt: input.state?.updatedAt ?? Date.now(), |
| 77 | 85 | }); |
| 78 | 86 | |
| 79 | −export const loadRuntimeLocalWorkspacePolicies = (workspaceId: WorkspaceId) => | |
| 87 | +export const loadRuntimeLocalScopePolicies = (scopeId: ScopeId) => | |
| 80 | 88 | Effect.gen(function* () { |
| 81 | − const runtimeLocalWorkspace = | |
| 82 | − yield* requireRuntimeLocalWorkspace(workspaceId); | |
| 83 | − const workspaceConfigStore = yield* WorkspaceConfigStore; | |
| 84 | − const workspaceStateStore = yield* WorkspaceStateStore; | |
| 85 | − const loadedConfig = yield* workspaceConfigStore.load(); | |
| 86 | − const workspaceState = yield* workspaceStateStore.load(); | |
| 89 | + const runtimeLocalScope = | |
| 90 | + yield* requireRuntimeLocalScope(scopeId); | |
| 91 | + const scopeConfigStore = yield* ScopeConfigStore; | |
| 92 | + const scopeStateStore = yield* ScopeStateStore; | |
| 93 | + const loadedConfig = yield* scopeConfigStore.load(); | |
| 94 | + const scopeState = yield* scopeStateStore.load(); | |
| 87 | 95 | |
| 88 | 96 | const policies = Object.entries(loadedConfig.config?.policies ?? {}).map( |
| 89 | 97 | ([key, policyConfig]) => |
| 90 | − toLocalWorkspacePolicy({ | |
| 91 | − workspaceId, | |
| 92 | − workspaceStableKey: workspacePolicyStableKey({ | |
| 93 | − workspaceId, | |
| 94 | − workspaceRoot: runtimeLocalWorkspace.workspace.workspaceRoot, | |
| 98 | + toLocalScopePolicy({ | |
| 99 | + scopeId, | |
| 100 | + scopeStableKey: scopePolicyStableKey({ | |
| 101 | + scopeId, | |
| 102 | + scopeRoot: runtimeLocalScope.scope.scopeRoot, | |
| 95 | 103 | }), |
| 96 | 104 | key, |
| 97 | 105 | policyConfig, |
| 98 | − state: workspaceState.policies[key], | |
| 106 | + state: scopeState.policies[key], | |
| 99 | 107 | }), |
| 100 | 108 | ); |
| 101 | 109 | |
| 102 | 110 | return { |
| 103 | − runtimeLocalWorkspace, | |
| 111 | + runtimeLocalScope, | |
| 104 | 112 | loadedConfig, |
| 105 | − workspaceState, | |
| 113 | + scopeState, | |
| 106 | 114 | policies, |
| 107 | 115 | }; |
| 108 | 116 | }); |
| 109 | 117 | |
| 110 | 118 | const writeLocalPolicyFiles = (input: { |
| 111 | 119 | operation: OperationErrors; |
| 112 | − workspaceConfigStore: WorkspaceConfigStoreShape; | |
| 113 | − workspaceStateStore: WorkspaceStateStoreShape; | |
| 120 | + scopeConfigStore: ScopeConfigStoreShape; | |
| 121 | + scopeStateStore: ScopeStateStoreShape; | |
| 114 | 122 | projectConfig: LocalExecutorConfig; |
| 115 | − workspaceState: LocalWorkspaceState; | |
| 123 | + scopeState: LocalScopeState; | |
| 116 | 124 | }) => |
| 117 | 125 | Effect.all( |
| 118 | 126 | [ |
| 119 | − input.workspaceConfigStore.writeProject({ | |
| 127 | + input.scopeConfigStore.writeProject({ | |
| 120 | 128 | config: input.projectConfig, |
| 121 | 129 | }), |
| 122 | − input.workspaceStateStore.write({ | |
| 123 | − state: input.workspaceState, | |
| 130 | + input.scopeStateStore.write({ | |
| 131 | + state: input.scopeState, | |
| 124 | 132 | }), |
| 125 | 133 | ], |
| 126 | 134 | { discard: true }, |
| @@ -128,16 +136,16 @@ const writeLocalPolicyFiles = (input: { · 1 unmodified line | ||
| 128 | 136 | Effect.mapError((cause) => |
| 129 | 137 | input.operation.unknownStorage( |
| 130 | 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 | 145 | operation: OperationErrors, |
| 138 | − workspaceId: WorkspaceId, | |
| 146 | + scopeId: ScopeId, | |
| 139 | 147 | ) => |
| 140 | − requireRuntimeLocalWorkspace(workspaceId).pipe( | |
| 148 | + requireRuntimeLocalScope(scopeId).pipe( | |
| 141 | 149 | Effect.mapError((cause) => |
| 142 | 150 | operation.notFound( |
| 143 | 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 | 158 | Effect.gen(function* () { |
| 151 | − yield* loadWorkspacePolicyContext(policyOps.list, workspaceId); | |
| 152 | − const localWorkspace = yield* loadRuntimeLocalWorkspacePolicies( | |
| 153 | − workspaceId, | |
| 159 | + yield* loadScopePolicyContext(policyOps.list, scopeId); | |
| 160 | + const localScope = yield* loadRuntimeLocalScopePolicies( | |
| 161 | + scopeId, | |
| 154 | 162 | ).pipe( |
| 155 | 163 | Effect.mapError((cause) => |
| 156 | 164 | policyOps.list.unknownStorage( |
| 157 | 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 | 173 | export const createPolicy = (input: { |
| 166 | − workspaceId: WorkspaceId; | |
| 174 | + scopeId: ScopeId; | |
| 167 | 175 | payload: CreatePolicyPayload; |
| 168 | 176 | }) => |
| 169 | 177 | Effect.gen(function* () { |
| 170 | − const runtimeLocalWorkspace = yield* loadWorkspacePolicyContext( | |
| 178 | + const runtimeLocalScope = yield* loadScopePolicyContext( | |
| 171 | 179 | policyOps.create, |
| 172 | − input.workspaceId, | |
| 180 | + input.scopeId, | |
| 173 | 181 | ); |
| 174 | − const workspaceConfigStore = yield* WorkspaceConfigStore; | |
| 175 | − const workspaceStateStore = yield* WorkspaceStateStore; | |
| 176 | − const localWorkspace = yield* loadRuntimeLocalWorkspacePolicies( | |
| 177 | − input.workspaceId, | |
| 182 | + const scopeConfigStore = yield* ScopeConfigStore; | |
| 183 | + const scopeStateStore = yield* ScopeStateStore; | |
| 184 | + const localScope = yield* loadRuntimeLocalScopePolicies( | |
| 185 | + input.scopeId, | |
| 178 | 186 | ).pipe( |
| 179 | 187 | Effect.mapError((cause) => |
| 180 | 188 | policyOps.create.unknownStorage( |
| 181 | 189 | cause, |
| 182 | − "Failed loading local workspace policies", | |
| 190 | + "Failed loading local scope policies", | |
| 183 | 191 | ), |
| 184 | 192 | ), |
| 185 | 193 | ); |
| 186 | 194 | const now = Date.now(); |
| 187 | 195 | const projectConfig = cloneJson( |
| 188 | − localWorkspace.loadedConfig.projectConfig ?? {}, | |
| 196 | + localScope.loadedConfig.projectConfig ?? {}, | |
| 189 | 197 | ); |
| 190 | 198 | const policies = { ...projectConfig.policies }; |
| 191 | 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]; | |
| 214 | − const workspaceState: LocalWorkspaceState = { | |
| 215 | − ...localWorkspace.workspaceState, | |
| 221 | + const existingState = localScope.scopeState.policies[key]; | |
| 222 | + const scopeState: LocalScopeState = { | |
| 223 | + ...localScope.scopeState, | |
| 216 | 224 | policies: { |
| 217 | − ...localWorkspace.workspaceState.policies, | |
| 225 | + ...localScope.scopeState.policies, | |
| 218 | 226 | [key]: { |
| 219 | 227 | id: |
| 220 | 228 | existingState?.id ?? |
| 221 | 229 | localPolicyIdForKey({ |
| 222 | − workspaceStableKey: workspacePolicyStableKey({ | |
| 223 | − workspaceId: input.workspaceId, | |
| 224 | − workspaceRoot: runtimeLocalWorkspace.workspace.workspaceRoot, | |
| 230 | + scopeStableKey: scopePolicyStableKey({ | |
| 231 | + scopeId: input.scopeId, | |
| 232 | + scopeRoot: runtimeLocalScope.scope.scopeRoot, | |
| 225 | 233 | }), |
| 226 | 234 | key, |
| 227 | 235 | }), |
| @@ -233,91 +241,91 @@ export const createPolicy = (input: { · 5 unmodified lines | ||
| 233 | 241 | |
| 234 | 242 | yield* writeLocalPolicyFiles({ |
| 235 | 243 | operation: policyOps.create, |
| 236 | − workspaceConfigStore, | |
| 237 | − workspaceStateStore, | |
| 244 | + scopeConfigStore, | |
| 245 | + scopeStateStore, | |
| 238 | 246 | projectConfig: { |
| 239 | 247 | ...projectConfig, |
| 240 | 248 | policies, |
| 241 | 249 | }, |
| 242 | − workspaceState, | |
| 250 | + scopeState, | |
| 243 | 251 | }); |
| 244 | 252 | |
| 245 | − return toLocalWorkspacePolicy({ | |
| 246 | − workspaceId: input.workspaceId, | |
| 247 | − workspaceStableKey: workspacePolicyStableKey({ | |
| 248 | − workspaceId: input.workspaceId, | |
| 249 | − workspaceRoot: runtimeLocalWorkspace.workspace.workspaceRoot, | |
| 253 | + return toLocalScopePolicy({ | |
| 254 | + scopeId: input.scopeId, | |
| 255 | + scopeStableKey: scopePolicyStableKey({ | |
| 256 | + scopeId: input.scopeId, | |
| 257 | + scopeRoot: runtimeLocalScope.scope.scopeRoot, | |
| 250 | 258 | }), |
| 251 | 259 | key, |
| 252 | 260 | policyConfig: policies[key]!, |
| 253 | − state: workspaceState.policies[key], | |
| 261 | + state: scopeState.policies[key], | |
| 254 | 262 | }); |
| 255 | 263 | }); |
| 256 | 264 | |
| 257 | 265 | export const getPolicy = (input: { |
| 258 | − workspaceId: WorkspaceId; | |
| 266 | + scopeId: ScopeId; | |
| 259 | 267 | policyId: PolicyId; |
| 260 | 268 | }) => |
| 261 | 269 | Effect.gen(function* () { |
| 262 | − yield* loadWorkspacePolicyContext(policyOps.get, input.workspaceId); | |
| 263 | − const localWorkspace = yield* loadRuntimeLocalWorkspacePolicies( | |
| 264 | − input.workspaceId, | |
| 270 | + yield* loadScopePolicyContext(policyOps.get, input.scopeId); | |
| 271 | + const localScope = yield* loadRuntimeLocalScopePolicies( | |
| 272 | + input.scopeId, | |
| 265 | 273 | ).pipe( |
| 266 | 274 | Effect.mapError((cause) => |
| 267 | 275 | policyOps.get.unknownStorage( |
| 268 | 276 | cause, |
| 269 | − "Failed loading local workspace policies", | |
| 277 | + "Failed loading local scope policies", | |
| 270 | 278 | ), |
| 271 | 279 | ), |
| 272 | 280 | ); |
| 273 | 281 | const policy = |
| 274 | − localWorkspace.policies.find( | |
| 282 | + localScope.policies.find( | |
| 275 | 283 | (candidate) => candidate.id === input.policyId, |
| 276 | 284 | ) ?? null; |
| 277 | 285 | if (policy === null) { |
| 278 | 286 | return yield* policyOps.get.notFound( |
| 279 | 287 | "Policy not found", |
| 280 | − `workspaceId=${input.workspaceId} policyId=${input.policyId}`, | |
| 288 | + `scopeId=${input.scopeId} policyId=${input.policyId}`, | |
| 281 | 289 | ); |
| 282 | 290 | } |
| 283 | 291 | return policy; |
| 284 | 292 | }); |
| 285 | 293 | |
| 286 | 294 | export const updatePolicy = (input: { |
| 287 | − workspaceId: WorkspaceId; | |
| 295 | + scopeId: ScopeId; | |
| 288 | 296 | policyId: PolicyId; |
| 289 | 297 | payload: UpdatePolicyPayload; |
| 290 | 298 | }) => |
| 291 | 299 | Effect.gen(function* () { |
| 292 | − const runtimeLocalWorkspace = yield* loadWorkspacePolicyContext( | |
| 300 | + const runtimeLocalScope = yield* loadScopePolicyContext( | |
| 293 | 301 | policyOps.update, |
| 294 | − input.workspaceId, | |
| 302 | + input.scopeId, | |
| 295 | 303 | ); |
| 296 | − const workspaceConfigStore = yield* WorkspaceConfigStore; | |
| 297 | − const workspaceStateStore = yield* WorkspaceStateStore; | |
| 298 | − const localWorkspace = yield* loadRuntimeLocalWorkspacePolicies( | |
| 299 | − input.workspaceId, | |
| 304 | + const scopeConfigStore = yield* ScopeConfigStore; | |
| 305 | + const scopeStateStore = yield* ScopeStateStore; | |
| 306 | + const localScope = yield* loadRuntimeLocalScopePolicies( | |
| 307 | + input.scopeId, | |
| 300 | 308 | ).pipe( |
| 301 | 309 | Effect.mapError((cause) => |
| 302 | 310 | policyOps.update.unknownStorage( |
| 303 | 311 | cause, |
| 304 | − "Failed loading local workspace policies", | |
| 312 | + "Failed loading local scope policies", | |
| 305 | 313 | ), |
| 306 | 314 | ), |
| 307 | 315 | ); |
| 308 | 316 | const existing = |
| 309 | − localWorkspace.policies.find( | |
| 317 | + localScope.policies.find( | |
| 310 | 318 | (candidate) => candidate.id === input.policyId, |
| 311 | 319 | ) ?? null; |
| 312 | 320 | if (existing === null) { |
| 313 | 321 | return yield* policyOps.update.notFound( |
| 314 | 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 | 327 | const projectConfig = cloneJson( |
| 320 | − localWorkspace.loadedConfig.projectConfig ?? {}, | |
| 328 | + localScope.loadedConfig.projectConfig ?? {}, | |
| 321 | 329 | ); |
| 322 | 330 | const policies = { ...projectConfig.policies }; |
| 323 | 331 | const existingConfig = policies[existing.key]!; |
| @@ -345,11 +353,11 @@ export const updatePolicy = (input: { · 21 unmodified lines | ||
| 345 | 353 | }; |
| 346 | 354 | |
| 347 | 355 | const updatedAt = Date.now(); |
| 348 | − const existingState = localWorkspace.workspaceState.policies[existing.key]; | |
| 349 | − const workspaceState: LocalWorkspaceState = { | |
| 350 | − ...localWorkspace.workspaceState, | |
| 356 | + const existingState = localScope.scopeState.policies[existing.key]; | |
| 357 | + const scopeState: LocalScopeState = { | |
| 358 | + ...localScope.scopeState, | |
| 351 | 359 | policies: { |
| 352 | − ...localWorkspace.workspaceState.policies, | |
| 360 | + ...localScope.scopeState.policies, | |
| 353 | 361 | [existing.key]: { |
| 354 | 362 | id: existing.id, |
| 355 | 363 | createdAt: existingState?.createdAt ?? existing.createdAt, |
| @@ -360,50 +368,50 @@ export const updatePolicy = (input: { · 4 unmodified lines | ||
| 360 | 368 | |
| 361 | 369 | yield* writeLocalPolicyFiles({ |
| 362 | 370 | operation: policyOps.update, |
| 363 | − workspaceConfigStore, | |
| 364 | − workspaceStateStore, | |
| 371 | + scopeConfigStore, | |
| 372 | + scopeStateStore, | |
| 365 | 373 | projectConfig: { |
| 366 | 374 | ...projectConfig, |
| 367 | 375 | policies, |
| 368 | 376 | }, |
| 369 | − workspaceState, | |
| 377 | + scopeState, | |
| 370 | 378 | }); |
| 371 | 379 | |
| 372 | − return toLocalWorkspacePolicy({ | |
| 373 | − workspaceId: input.workspaceId, | |
| 374 | − workspaceStableKey: workspacePolicyStableKey({ | |
| 375 | − workspaceId: input.workspaceId, | |
| 376 | − workspaceRoot: runtimeLocalWorkspace.workspace.workspaceRoot, | |
| 380 | + return toLocalScopePolicy({ | |
| 381 | + scopeId: input.scopeId, | |
| 382 | + scopeStableKey: scopePolicyStableKey({ | |
| 383 | + scopeId: input.scopeId, | |
| 384 | + scopeRoot: runtimeLocalScope.scope.scopeRoot, | |
| 377 | 385 | }), |
| 378 | 386 | key: existing.key, |
| 379 | 387 | policyConfig: policies[existing.key]!, |
| 380 | − state: workspaceState.policies[existing.key], | |
| 388 | + state: scopeState.policies[existing.key], | |
| 381 | 389 | }); |
| 382 | 390 | }); |
| 383 | 391 | |
| 384 | 392 | export const removePolicy = (input: { |
| 385 | − workspaceId: WorkspaceId; | |
| 393 | + scopeId: ScopeId; | |
| 386 | 394 | policyId: PolicyId; |
| 387 | 395 | }) => |
| 388 | 396 | Effect.gen(function* () { |
| 389 | − const runtimeLocalWorkspace = yield* loadWorkspacePolicyContext( | |
| 397 | + const runtimeLocalScope = yield* loadScopePolicyContext( | |
| 390 | 398 | policyOps.remove, |
| 391 | − input.workspaceId, | |
| 399 | + input.scopeId, | |
| 392 | 400 | ); |
| 393 | − const workspaceConfigStore = yield* WorkspaceConfigStore; | |
| 394 | − const workspaceStateStore = yield* WorkspaceStateStore; | |
| 395 | − const localWorkspace = yield* loadRuntimeLocalWorkspacePolicies( | |
| 396 | − input.workspaceId, | |
| 401 | + const scopeConfigStore = yield* ScopeConfigStore; | |
| 402 | + const scopeStateStore = yield* ScopeStateStore; | |
| 403 | + const localScope = yield* loadRuntimeLocalScopePolicies( | |
| 404 | + input.scopeId, | |
| 397 | 405 | ).pipe( |
| 398 | 406 | Effect.mapError((cause) => |
| 399 | 407 | policyOps.remove.unknownStorage( |
| 400 | 408 | cause, |
| 401 | − "Failed loading local workspace policies", | |
| 409 | + "Failed loading local scope policies", | |
| 402 | 410 | ), |
| 403 | 411 | ), |
| 404 | 412 | ); |
| 405 | 413 | const existing = |
| 406 | − localWorkspace.policies.find( | |
| 414 | + localScope.policies.find( | |
| 407 | 415 | (candidate) => candidate.id === input.policyId, |
| 408 | 416 | ) ?? null; |
| 409 | 417 | if (existing === null) { |
| @@ -411,23 +419,23 @@ export const removePolicy = (input: { · 1 unmodified line | ||
| 411 | 419 | } |
| 412 | 420 | |
| 413 | 421 | const projectConfig = cloneJson( |
| 414 | − localWorkspace.loadedConfig.projectConfig ?? {}, | |
| 422 | + localScope.loadedConfig.projectConfig ?? {}, | |
| 415 | 423 | ); |
| 416 | 424 | const policies = { ...projectConfig.policies }; |
| 417 | 425 | delete policies[existing.key]; |
| 418 | 426 | |
| 419 | 427 | const { [existing.key]: _removedPolicy, ...remainingPolicies } = |
| 420 | − localWorkspace.workspaceState.policies; | |
| 428 | + localScope.scopeState.policies; | |
| 421 | 429 | yield* writeLocalPolicyFiles({ |
| 422 | 430 | operation: policyOps.remove, |
| 423 | − workspaceConfigStore, | |
| 424 | − workspaceStateStore, | |
| 431 | + scopeConfigStore, | |
| 432 | + scopeStateStore, | |
| 425 | 433 | projectConfig: { |
| 426 | 434 | ...projectConfig, |
| 427 | 435 | policies, |
| 428 | 436 | }, |
| 429 | − workspaceState: { | |
| 430 | − ...localWorkspace.workspaceState, | |
| 437 | + scopeState: { | |
| 438 | + ...localScope.scopeState, | |
| 431 | 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 | 4 | import { |
| 3 | − type AccountId, | |
| 5 | + type ScopeId, | |
| 4 | 6 | AuthGrantSetJsonSchema, |
| 5 | 7 | McpOAuthAuthArtifactConfigJsonSchema, |
| 6 | 8 | McpOAuthAuthArtifactKind, |
| @@ -35,8 +37,10 @@ import * as Schema from "effect/Schema"; · 28 unmodified lines | ||
| 35 | 37 | import type { |
| 36 | 38 | ResolveSecretMaterial, |
| 37 | 39 | SecretMaterialResolveContext, |
| 38 | −} from "../workspace/secret-material-providers"; | |
| 39 | −import { runtimeEffectError } from "../effect-errors"; | |
| 40 | +} from "../scope/secret-material-providers"; | |
| 41 | +import { | |
| 42 | + runtimeEffectError, | |
| 43 | +} from "../effect-errors"; | |
| 40 | 44 | |
| 41 | 45 | export type ResolvedSourceAuthMaterial = { |
| 42 | 46 | placements: ReadonlyArray<RequestPlacement>; |
| @@ -154,7 +158,7 @@ export const authArtifactFromSourceAuth = (input: { · 111 unmodified lines | ||
| 154 | 158 | source: Source; |
| 155 | 159 | auth: SourceAuth; |
| 156 | 160 | slot: CredentialSlot; |
| 157 | − actorAccountId?: AccountId | null; | |
| 161 | + actorScopeId?: ScopeId | null; | |
| 158 | 162 | existingAuthArtifactId?: AuthArtifact["id"] | null; |
| 159 | 163 | }): AuthArtifact | null => { |
| 160 | 164 | if (input.auth.kind === "none") { |
| @@ -170,9 +174,9 @@ export const authArtifactFromSourceAuth = (input: { · 9 unmodified lines | ||
| 170 | 174 | if (input.auth.kind === "bearer") { |
| 171 | 175 | return { |
| 172 | 176 | id, |
| 173 | − workspaceId: input.source.workspaceId, | |
| 177 | + scopeId: input.source.scopeId, | |
| 174 | 178 | sourceId: input.source.id, |
| 175 | − actorAccountId: input.actorAccountId ?? null, | |
| 179 | + actorScopeId: input.actorScopeId ?? null, | |
| 176 | 180 | slot: input.slot, |
| 177 | 181 | artifactKind: StaticBearerAuthArtifactKind, |
| 178 | 182 | configJson: encodeStaticBearerAuthArtifactConfig({ |
| @@ -189,9 +193,9 @@ export const authArtifactFromSourceAuth = (input: { · 10 unmodified lines | ||
| 189 | 193 | if (input.auth.kind === "oauth2_authorized_user") { |
| 190 | 194 | return { |
| 191 | 195 | id, |
| 192 | − workspaceId: input.source.workspaceId, | |
| 196 | + scopeId: input.source.scopeId, | |
| 193 | 197 | sourceId: input.source.id, |
| 194 | − actorAccountId: input.actorAccountId ?? null, | |
| 198 | + actorScopeId: input.actorScopeId ?? null, | |
| 195 | 199 | slot: input.slot, |
| 196 | 200 | artifactKind: RefreshableOAuth2AuthorizedUserAuthArtifactKind, |
| 197 | 201 | configJson: encodeRefreshableOAuth2AuthorizedUserAuthArtifactConfig({ |
| @@ -212,9 +216,9 @@ export const authArtifactFromSourceAuth = (input: { · 14 unmodified lines | ||
| 212 | 216 | if (input.auth.kind === "provider_grant_ref") { |
| 213 | 217 | return { |
| 214 | 218 | id, |
| 215 | − workspaceId: input.source.workspaceId, | |
| 219 | + scopeId: input.source.scopeId, | |
| 216 | 220 | sourceId: input.source.id, |
| 217 | − actorAccountId: input.actorAccountId ?? null, | |
| 221 | + actorScopeId: input.actorScopeId ?? null, | |
| 218 | 222 | slot: input.slot, |
| 219 | 223 | artifactKind: ProviderGrantRefAuthArtifactKind, |
| 220 | 224 | configJson: encodeProviderGrantRefAuthArtifactConfig({ |
| @@ -233,9 +237,9 @@ export const authArtifactFromSourceAuth = (input: { · 12 unmodified lines | ||
| 233 | 237 | if (input.auth.kind === "mcp_oauth") { |
| 234 | 238 | return { |
| 235 | 239 | id, |
| 236 | − workspaceId: input.source.workspaceId, | |
| 240 | + scopeId: input.source.scopeId, | |
| 237 | 241 | sourceId: input.source.id, |
| 238 | − actorAccountId: input.actorAccountId ?? null, | |
| 242 | + actorScopeId: input.actorScopeId ?? null, | |
| 239 | 243 | slot: input.slot, |
| 240 | 244 | artifactKind: McpOAuthAuthArtifactKind, |
| 241 | 245 | configJson: encodeMcpOAuthAuthArtifactConfig({ |
| @@ -259,9 +263,9 @@ export const authArtifactFromSourceAuth = (input: { · 17 unmodified lines | ||
| 259 | 263 | |
| 260 | 264 | return { |
| 261 | 265 | id, |
| 262 | − workspaceId: input.source.workspaceId, | |
| 266 | + scopeId: input.source.scopeId, | |
| 263 | 267 | sourceId: input.source.id, |
| 264 | − actorAccountId: input.actorAccountId ?? null, | |
| 268 | + actorScopeId: input.actorScopeId ?? null, | |
| 265 | 269 | slot: input.slot, |
| 266 | 270 | artifactKind: StaticOAuth2AuthArtifactKind, |
| 267 | 271 | configJson: encodeStaticOAuth2AuthArtifactConfig({ |
| @@ -16,18 +16,31 @@ import { · 15 unmodified lines | ||
| 16 | 16 | import * as Effect from "effect/Effect"; |
| 17 | 17 | import * as Option from "effect/Option"; |
| 18 | 18 | |
| 19 | −import type { ExecutorStateStoreShape } from "../executor-state-store"; | |
| 20 | −import { resolveAuthArtifactMaterial, type ResolvedSourceAuthMaterial } from "./auth-artifacts"; | |
| 19 | +import type { | |
| 20 | + ExecutorStateStoreShape, | |
| 21 | +} from "../executor-state-store"; | |
| 22 | +import { | |
| 23 | + resolveAuthArtifactMaterial, | |
| 24 | + type ResolvedSourceAuthMaterial, | |
| 25 | +} from "./auth-artifacts"; | |
| 21 | 26 | import { |
| 22 | 27 | type DeleteSecretMaterial, |
| 23 | 28 | type ResolveSecretMaterial, |
| 24 | 29 | type SecretMaterialResolveContext, |
| 25 | 30 | type StoreSecretMaterial, |
| 26 | −} from "../workspace/secret-material-providers"; | |
| 27 | −import { refreshOAuth2AccessToken } from "./oauth2-pkce"; | |
| 28 | −import type { OAuth2TokenResponse } from "./oauth2-pkce"; | |
| 29 | −import { createPersistedMcpAuthProvider } from "./mcp-auth-provider"; | |
| 30 | −import { runtimeEffectError } from "../effect-errors"; | |
| 31 | +} from "../scope/secret-material-providers"; | |
| 32 | +import { | |
| 33 | + refreshOAuth2AccessToken, | |
| 34 | +} from "./oauth2-pkce"; | |
| 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 | 45 | const LEASE_REFRESH_SKEW_MS = 60_000; |
| 33 | 46 | |
| @@ -134,9 +147,9 @@ const refreshRefreshableOauth2AuthorizedUserArtifact = (input: { · 100 unmodified lines | ||
| 134 | 147 | const nextLease: AuthLease = { |
| 135 | 148 | id: input.lease?.id ?? AuthLeaseIdSchema.make(`auth_lease_${crypto.randomUUID()}`), |
| 136 | 149 | authArtifactId: input.artifact.id, |
| 137 | − workspaceId: input.artifact.workspaceId, | |
| 150 | + scopeId: input.artifact.scopeId, | |
| 138 | 151 | sourceId: input.artifact.sourceId, |
| 139 | − actorAccountId: input.artifact.actorAccountId, | |
| 152 | + actorScopeId: input.artifact.actorScopeId, | |
| 140 | 153 | slot: input.artifact.slot, |
| 141 | 154 | placementsTemplateJson: encodeLeasePlacementTemplatesJson([ |
| 142 | 155 | { |
| @@ -169,7 +182,7 @@ const refreshRefreshableOauth2AuthorizedUserArtifact = (input: { · 26 unmodified lines | ||
| 169 | 182 | return nextLease; |
| 170 | 183 | }); |
| 171 | 184 | |
| 172 | −const workspaceOauthClientSecretRef = (input: { | |
| 185 | +const scopeOauthClientSecretRef = (input: { | |
| 173 | 186 | clientSecretProviderId: string | null; |
| 174 | 187 | clientSecretHandle: string | null; |
| 175 | 188 | }): SecretRef | null => |
| @@ -212,9 +225,9 @@ const refreshProviderGrantRefArtifact = (input: { · 36 unmodified lines | ||
| 212 | 225 | } |
| 213 | 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 | 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 | 232 | const oauthClient = oauthClientOption.value; |
| 220 | 233 | |
| @@ -222,7 +235,7 @@ const refreshProviderGrantRefArtifact = (input: { · 1 unmodified line | ||
| 222 | 235 | ref: grant.refreshToken, |
| 223 | 236 | context: input.context, |
| 224 | 237 | }); |
| 225 | − const clientSecretRef = workspaceOauthClientSecretRef(oauthClient); | |
| 238 | + const clientSecretRef = scopeOauthClientSecretRef(oauthClient); | |
| 226 | 239 | const clientSecret = clientSecretRef |
| 227 | 240 | ? yield* input.resolveSecretMaterial({ |
| 228 | 241 | ref: clientSecretRef, |
| @@ -277,9 +290,9 @@ const refreshProviderGrantRefArtifact = (input: { · 48 unmodified lines | ||
| 277 | 290 | const nextLease: AuthLease = { |
| 278 | 291 | id: input.lease?.id ?? AuthLeaseIdSchema.make(`auth_lease_${crypto.randomUUID()}`), |
| 279 | 292 | authArtifactId: input.artifact.id, |
| 280 | − workspaceId: input.artifact.workspaceId, | |
| 293 | + scopeId: input.artifact.scopeId, | |
| 281 | 294 | sourceId: input.artifact.sourceId, |
| 282 | − actorAccountId: input.artifact.actorAccountId, | |
| 295 | + actorScopeId: input.artifact.actorScopeId, | |
| 283 | 296 | slot: input.artifact.slot, |
| 284 | 297 | placementsTemplateJson: encodeLeasePlacementTemplatesJson([ |
| 285 | 298 | { |
| @@ -363,9 +376,9 @@ export const upsertOauth2AuthorizedUserLeaseFromTokenResponse = (input: { · 77 unmodified lines | ||
| 363 | 376 | const nextLease: AuthLease = { |
| 364 | 377 | id: existingLease?.id ?? AuthLeaseIdSchema.make(`auth_lease_${crypto.randomUUID()}`), |
| 365 | 378 | authArtifactId: input.artifact.id, |
| 366 | − workspaceId: input.artifact.workspaceId, | |
| 379 | + scopeId: input.artifact.scopeId, | |
| 367 | 380 | sourceId: input.artifact.sourceId, |
| 368 | − actorAccountId: input.artifact.actorAccountId, | |
| 381 | + actorScopeId: input.artifact.actorScopeId, | |
| 369 | 382 | slot: input.artifact.slot, |
| 370 | 383 | placementsTemplateJson: encodeLeasePlacementTemplatesJson([ |
| 371 | 384 | { |
| @@ -20,13 +20,15 @@ import { · 19 unmodified lines | ||
| 20 | 20 | import * as Effect from "effect/Effect"; |
| 21 | 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 | 26 | import { |
| 25 | 27 | type DeleteSecretMaterial, |
| 26 | 28 | type ResolveSecretMaterial, |
| 27 | 29 | type SecretMaterialResolveContext, |
| 28 | 30 | type StoreSecretMaterial, |
| 29 | −} from "../workspace/secret-material-providers"; | |
| 31 | +} from "../scope/secret-material-providers"; | |
| 30 | 32 | |
| 31 | 33 | const encodeMcpOAuthAuthArtifactConfig = Schema.encodeSync( |
| 32 | 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 | 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 | 16 | const toError = (cause: unknown): Error => |
| 9 | 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 | 5 | import * as Effect from "effect/Effect"; |
| 4 | 6 | |
| @@ -1,7 +1,7 @@ | ||
| 1 | 1 | import type { |
| 2 | 2 | AuthArtifact, |
| 3 | 3 | ProviderAuthGrant, |
| 4 | − WorkspaceId, | |
| 4 | + ScopeId, | |
| 5 | 5 | } from "#schema"; |
| 6 | 6 | import { |
| 7 | 7 | decodeProviderGrantRefAuthArtifactConfig, |
| @@ -11,8 +11,10 @@ import * as Option from "effect/Option"; · 3 unmodified lines | ||
| 11 | 11 | |
| 12 | 12 | import { |
| 13 | 13 | type DeleteSecretMaterial, |
| 14 | −} from "../workspace/secret-material-providers"; | |
| 15 | −import type { ExecutorStateStoreShape } from "../executor-state-store"; | |
| 14 | +} from "../scope/secret-material-providers"; | |
| 15 | +import type { | |
| 16 | + ExecutorStateStoreShape, | |
| 17 | +} from "../executor-state-store"; | |
| 16 | 18 | |
| 17 | 19 | const providerGrantRefFromArtifact = ( |
| 18 | 20 | artifact: Pick<AuthArtifact, "artifactKind" | "configJson">, |
| @@ -24,11 +26,11 @@ export const providerGrantIdFromArtifact = ( · 5 unmodified lines | ||
| 24 | 26 | providerGrantRefFromArtifact(artifact)?.grantId ?? null; |
| 25 | 27 | |
| 26 | 28 | export const listProviderGrantRefArtifacts = (executorState: ExecutorStateStoreShape, input: { |
| 27 | − workspaceId: WorkspaceId; | |
| 29 | + scopeId: ScopeId; | |
| 28 | 30 | grantId?: ProviderAuthGrant["id"] | null; |
| 29 | 31 | }): Effect.Effect<readonly AuthArtifact[], Error, never> => |
| 30 | 32 | Effect.map( |
| 31 | − executorState.authArtifacts.listByWorkspaceId(input.workspaceId), | |
| 33 | + executorState.authArtifacts.listByScopeId(input.scopeId), | |
| 32 | 34 | (artifacts) => |
| 33 | 35 | artifacts.filter((artifact) => { |
| 34 | 36 | const grantId = providerGrantIdFromArtifact(artifact); |
| @@ -54,7 +56,7 @@ export const clearProviderGrantOrphanedAt = (executorState: ExecutorStateStoreSh · 19 unmodified lines | ||
| 54 | 56 | }); |
| 55 | 57 | |
| 56 | 58 | export const markProviderGrantOrphanedIfUnused = (executorState: ExecutorStateStoreShape, input: { |
| 57 | − workspaceId: WorkspaceId; | |
| 59 | + scopeId: ScopeId; | |
| 58 | 60 | grantId: ProviderAuthGrant["id"]; |
| 59 | 61 | }): Effect.Effect<boolean, Error, never> => |
| 60 | 62 | Effect.gen(function* () { |
| @@ -64,7 +66,7 @@ export const markProviderGrantOrphanedIfUnused = (executorState: ExecutorStateSt · 3 unmodified lines | ||
| 64 | 66 | } |
| 65 | 67 | |
| 66 | 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 | 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 | 6 | import * as Effect from "effect/Effect"; |
| 3 | 7 | import * as Option from "effect/Option"; |
| 4 | 8 | |
| 5 | 9 | import { |
| 6 | 10 | AuthArtifactIdSchema, |
| 7 | 11 | SourceIdSchema, |
| 8 | − WorkspaceIdSchema, | |
| 12 | + ScopeIdSchema, | |
| 9 | 13 | type Source, |
| 10 | 14 | } from "#schema"; |
| 11 | 15 | |
| 12 | −import { resolveSourceAuthMaterialWithDeps } from "./source-auth-material"; | |
| 16 | +import { | |
| 17 | + resolveSourceAuthMaterialWithDeps, | |
| 18 | +} from "./source-auth-material"; | |
| 13 | 19 | |
| 14 | 20 | const makeSource = (overrides: Partial<Source> = {}): Source => ({ |
| 15 | 21 | id: SourceIdSchema.make("src_tool_artifacts"), |
| 16 | − workspaceId: WorkspaceIdSchema.make("ws_tool_artifacts"), | |
| 22 | + scopeId: ScopeIdSchema.make("ws_tool_artifacts"), | |
| 17 | 23 | name: "GitHub", |
| 18 | 24 | kind: "openapi", |
| 19 | 25 | endpoint: "https://api.github.com", |
| @@ -176,16 +182,16 @@ describe("source-auth-material", () => { · 156 unmodified lines | ||
| 176 | 182 | }, |
| 177 | 183 | auth: { kind: "none" }, |
| 178 | 184 | }), |
| 179 | − actorAccountId: null, | |
| 185 | + actorScopeId: null, | |
| 180 | 186 | executorState: { |
| 181 | 187 | authArtifacts: { |
| 182 | − getByWorkspaceSourceAndActor: () => | |
| 188 | + getByScopeSourceAndActor: () => | |
| 183 | 189 | Effect.succeed( |
| 184 | 190 | Option.some({ |
| 185 | 191 | id: AuthArtifactIdSchema.make("auth_artifact_mcp"), |
| 186 | − workspaceId: WorkspaceIdSchema.make("ws_tool_artifacts"), | |
| 192 | + scopeId: ScopeIdSchema.make("ws_tool_artifacts"), | |
| 187 | 193 | sourceId: SourceIdSchema.make("src_tool_artifacts"), |
| 188 | − actorAccountId: null, | |
| 194 | + actorScopeId: null, | |
| 189 | 195 | slot: "runtime", |
| 190 | 196 | artifactKind: "mcp_oauth", |
| 191 | 197 | configJson: JSON.stringify({ |
| @@ -1,5 +1,5 @@ | ||
| 1 | 1 | import type { |
| 2 | − AccountId, | |
| 2 | + ScopeId, | |
| 3 | 3 | CredentialSlot, |
| 4 | 4 | Source, |
| 5 | 5 | SourceAuth, |
| @@ -9,25 +9,32 @@ import * as Effect from "effect/Effect"; · 3 unmodified lines | ||
| 9 | 9 | import * as Layer from "effect/Layer"; |
| 10 | 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 | 16 | import { |
| 14 | 17 | authArtifactFromSourceAuth, |
| 15 | 18 | resolveAuthArtifactMaterial, |
| 16 | 19 | type ResolvedSourceAuthMaterial, |
| 17 | 20 | } from "./auth-artifacts"; |
| 18 | −import { resolveAuthArtifactMaterialWithLeases } from "./auth-leases"; | |
| 21 | +import { | |
| 22 | + resolveAuthArtifactMaterialWithLeases, | |
| 23 | +} from "./auth-leases"; | |
| 19 | 24 | import type { |
| 20 | 25 | DeleteSecretMaterial, |
| 21 | 26 | ResolveSecretMaterial, |
| 22 | 27 | SecretMaterialResolveContext, |
| 23 | 28 | StoreSecretMaterial, |
| 24 | −} from "../workspace/secret-material-providers"; | |
| 29 | +} from "../scope/secret-material-providers"; | |
| 25 | 30 | import { |
| 26 | 31 | SecretMaterialDeleterService, |
| 27 | 32 | SecretMaterialResolverService, |
| 28 | 33 | SecretMaterialStorerService, |
| 29 | −} from "../workspace/secret-material-providers"; | |
| 30 | −import { runtimeEffectError } from "../effect-errors"; | |
| 34 | +} from "../scope/secret-material-providers"; | |
| 35 | +import { | |
| 36 | + runtimeEffectError, | |
| 37 | +} from "../effect-errors"; | |
| 31 | 38 | |
| 32 | 39 | const authForSlot = (input: { |
| 33 | 40 | source: Source; |
| @@ -52,7 +59,7 @@ export type RuntimeSourceAuthMaterialShape = { · 18 unmodified lines | ||
| 52 | 59 | resolve: (input: { |
| 53 | 60 | source: Source; |
| 54 | 61 | slot?: CredentialSlot; |
| 55 | − actorAccountId?: AccountId | null; | |
| 62 | + actorScopeId?: ScopeId | null; | |
| 56 | 63 | context?: SecretMaterialResolveContext; |
| 57 | 64 | }) => Effect.Effect<ResolvedSourceAuthMaterial, Error, never>; |
| 58 | 65 | }; |
| @@ -64,7 +71,7 @@ export class RuntimeSourceAuthMaterialService extends Context.Tag( · 5 unmodified lines | ||
| 64 | 71 | export const resolveSourceAuthMaterialWithDeps = (input: { |
| 65 | 72 | source: Source; |
| 66 | 73 | slot?: CredentialSlot; |
| 67 | − actorAccountId?: AccountId | null; | |
| 74 | + actorScopeId?: ScopeId | null; | |
| 68 | 75 | executorState?: ExecutorStateStoreShape; |
| 69 | 76 | resolveSecretMaterial: ResolveSecretMaterial; |
| 70 | 77 | storeSecretMaterial?: StoreSecretMaterial; |
| @@ -81,10 +88,10 @@ export const resolveSourceAuthMaterialWithDeps = (input: { · 10 unmodified lines | ||
| 81 | 88 | : [slot] satisfies ReadonlyArray<CredentialSlot>; |
| 82 | 89 | |
| 83 | 90 | for (const candidateSlot of candidateSlots) { |
| 84 | − const artifactOption = yield* input.executorState.authArtifacts.getByWorkspaceSourceAndActor({ | |
| 85 | − workspaceId: input.source.workspaceId, | |
| 91 | + const artifactOption = yield* input.executorState.authArtifacts.getByScopeSourceAndActor({ | |
| 92 | + scopeId: input.source.scopeId, | |
| 86 | 93 | sourceId: input.source.id, |
| 87 | − actorAccountId: input.actorAccountId ?? null, | |
| 94 | + actorScopeId: input.actorScopeId ?? null, | |
| 88 | 95 | slot: candidateSlot, |
| 89 | 96 | }); |
| 90 | 97 | |
| @@ -108,7 +115,7 @@ export const resolveSourceAuthMaterialWithDeps = (input: { · 17 unmodified lines | ||
| 108 | 115 | slot, |
| 109 | 116 | }), |
| 110 | 117 | slot, |
| 111 | − actorAccountId: input.actorAccountId ?? null, | |
| 118 | + actorScopeId: input.actorScopeId ?? null, | |
| 112 | 119 | }); |
| 113 | 120 | |
| 114 | 121 | if (input.executorState !== undefined) { |
| @@ -140,7 +147,7 @@ export const resolveSourceAuthMaterialWithDeps = (input: { · 25 unmodified lines | ||
| 140 | 147 | export const resolveSourceAuthMaterial = (input: { |
| 141 | 148 | source: Source; |
| 142 | 149 | slot?: CredentialSlot; |
| 143 | − actorAccountId?: AccountId | null; | |
| 150 | + actorScopeId?: ScopeId | null; | |
| 144 | 151 | context?: SecretMaterialResolveContext; |
| 145 | 152 | }): Effect.Effect<ResolvedSourceAuthMaterial, Error, RuntimeSourceAuthMaterialService> => |
| 146 | 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"; | |
| 4 | −import type { ShapeSymbolId } from "@executor/ir/ids"; | |
| 5 | +import type { | |
| 6 | + ProjectedCatalog, | |
| 7 | +} from "@executor/ir/catalog"; | |
| 8 | +import type { | |
| 9 | + ShapeSymbolId, | |
| 10 | +} from "@executor/ir/ids"; | |
| 5 | 11 | import type { |
| 6 | 12 | CatalogV1, |
| 7 | 13 | DocumentationBlock, |
| @@ -1,4 +1,6 @@ | ||
| 1 | −import { format } from "prettier/standalone"; | |
| 1 | +import { | |
| 2 | + format, | |
| 3 | +} from "prettier/standalone"; | |
| 2 | 4 | import parserBabel from "prettier/plugins/babel"; |
| 3 | 5 | import parserEstree from "prettier/plugins/estree"; |
| 4 | 6 | import parserTypescript from "prettier/plugins/typescript"; |
| @@ -1,15 +1,24 @@ | ||
| 1 | 1 | import type { |
| 2 | − AccountId, | |
| 2 | + ScopeId, | |
| 3 | 3 | Source, |
| 4 | − WorkspaceId, | |
| 5 | 4 | } from "#schema"; |
| 6 | 5 | import * as Effect from "effect/Effect"; |
| 7 | 6 | |
| 8 | −import { RuntimeLocalWorkspaceService } from "../../workspace/runtime-context"; | |
| 9 | −import { SourceArtifactStore } from "../../workspace/storage"; | |
| 10 | −import { getSourceAdapterForSource } from "../../sources/source-adapters"; | |
| 11 | −import { RuntimeSourceStoreService } from "../../sources/source-store"; | |
| 12 | −import { RuntimeSourceCatalogSyncService } from "./sync"; | |
| 7 | +import { | |
| 8 | + RuntimeLocalScopeService, | |
| 9 | +} from "../../scope/runtime-context"; | |
| 10 | +import { | |
| 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 | 23 | const shouldReconcileSource = (source: Source): boolean => |
| 15 | 24 | source.enabled |
| @@ -17,23 +26,23 @@ const shouldReconcileSource = (source: Source): boolean => · 1 unmodified line | ||
| 17 | 26 | && getSourceAdapterForSource(source).catalogKind !== "internal"; |
| 18 | 27 | |
| 19 | 28 | export const reconcileMissingSourceCatalogArtifacts = (input: { |
| 20 | − workspaceId: WorkspaceId; | |
| 21 | − actorAccountId?: AccountId | null; | |
| 29 | + scopeId: ScopeId; | |
| 30 | + actorScopeId?: ScopeId | null; | |
| 22 | 31 | }): Effect.Effect< |
| 23 | 32 | void, |
| 24 | 33 | Error, |
| 25 | − | RuntimeLocalWorkspaceService | |
| 34 | + | RuntimeLocalScopeService | |
| 26 | 35 | | SourceArtifactStore |
| 27 | 36 | | RuntimeSourceStoreService |
| 28 | 37 | | RuntimeSourceCatalogSyncService |
| 29 | 38 | > => |
| 30 | 39 | Effect.gen(function* () { |
| 31 | − const runtimeLocalWorkspace = yield* RuntimeLocalWorkspaceService; | |
| 40 | + const runtimeLocalScope = yield* RuntimeLocalScopeService; | |
| 32 | 41 | const sourceStore = yield* RuntimeSourceStoreService; |
| 33 | 42 | const sourceArtifactStore = yield* SourceArtifactStore; |
| 34 | 43 | const sourceCatalogSync = yield* RuntimeSourceCatalogSyncService; |
| 35 | − const sources = yield* sourceStore.loadSourcesInWorkspace(input.workspaceId, { | |
| 36 | − actorAccountId: input.actorAccountId, | |
| 44 | + const sources = yield* sourceStore.loadSourcesInScope(input.scopeId, { | |
| 45 | + actorScopeId: input.actorScopeId, | |
| 37 | 46 | }); |
| 38 | 47 | |
| 39 | 48 | for (const source of sources) { |
| @@ -50,7 +59,7 @@ export const reconcileMissingSourceCatalogArtifacts = (input: { · 10 unmodified lines | ||
| 50 | 59 | |
| 51 | 60 | yield* sourceCatalogSync.sync({ |
| 52 | 61 | source, |
| 53 | − actorAccountId: input.actorAccountId, | |
| 62 | + actorScopeId: input.actorScopeId, | |
| 54 | 63 | }).pipe( |
| 55 | 64 | Effect.catchAll(() => Effect.void), |
| 56 | 65 | ); |
| @@ -58,7 +67,7 @@ export const reconcileMissingSourceCatalogArtifacts = (input: { · 1 unmodified line | ||
| 58 | 67 | }).pipe( |
| 59 | 68 | Effect.withSpan("source.catalog.reconcile_missing", { |
| 60 | 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 | 6 | import * as Effect from "effect/Effect"; |
| 3 | 7 | |
| 4 | 8 | import type { |
| @@ -10,7 +14,7 @@ import { · 5 unmodified lines | ||
| 10 | 14 | SourceCatalogIdSchema, |
| 11 | 15 | SourceCatalogRevisionIdSchema, |
| 12 | 16 | SourceIdSchema, |
| 13 | − WorkspaceIdSchema, | |
| 17 | + ScopeIdSchema, | |
| 14 | 18 | } from "#schema"; |
| 15 | 19 | |
| 16 | 20 | import { |
| @@ -27,7 +31,10 @@ import { · 10 unmodified lines | ||
| 27 | 31 | ScopeIdSchema, |
| 28 | 32 | ShapeSymbolIdSchema, |
| 29 | 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 | 38 | import { |
| 32 | 39 | createCatalogTypeProjector, |
| 33 | 40 | formatTypeNameSegment, |
| @@ -274,7 +281,7 @@ const createLoadedCatalog = (options?: { · 240 unmodified lines | ||
| 274 | 281 | |
| 275 | 282 | const source = { |
| 276 | 283 | id: SourceIdSchema.make("src_linear"), |
| 277 | − workspaceId: WorkspaceIdSchema.make("ws_linear"), | |
| 284 | + scopeId: ScopeIdSchema.make("ws_linear"), | |
| 278 | 285 | name: "Linear", |
| 279 | 286 | kind: "graphql-schema", |
| 280 | 287 | endpoint: "https://api.linear.app/graphql", |
| @@ -294,7 +301,7 @@ const createLoadedCatalog = (options?: { · 13 unmodified lines | ||
| 294 | 301 | |
| 295 | 302 | const sourceRecord = { |
| 296 | 303 | id: source.id, |
| 297 | − workspaceId: source.workspaceId, | |
| 304 | + scopeId: source.scopeId, | |
| 298 | 305 | catalogId: SourceCatalogIdSchema.make("catalog_linear"), |
| 299 | 306 | catalogRevisionId: SourceCatalogRevisionIdSchema.make("catalog_revision_linear"), |
| 300 | 307 | name: source.name, |
| @@ -3,11 +3,10 @@ import { · 2 unmodified lines | ||
| 3 | 3 | type ToolDescriptor as CatalogToolDescriptor, |
| 4 | 4 | } from "@executor/codemode-core"; |
| 5 | 5 | import type { |
| 6 | − AccountId, | |
| 6 | + ScopeId, | |
| 7 | 7 | Source, |
| 8 | 8 | StoredSourceRecord, |
| 9 | 9 | StoredSourceCatalogRevisionRecord, |
| 10 | − WorkspaceId, | |
| 11 | 10 | } from "#schema"; |
| 12 | 11 | import * as Context from "effect/Context"; |
| 13 | 12 | import * as Effect from "effect/Effect"; |
| @@ -19,7 +18,9 @@ import { · 5 unmodified lines | ||
| 19 | 18 | projectCatalogForAgentSdk, |
| 20 | 19 | type ProjectedCatalog, |
| 21 | 20 | } from "@executor/ir/catalog"; |
| 22 | −import type { ShapeSymbolId } from "@executor/ir/ids"; | |
| 21 | +import type { | |
| 22 | + ShapeSymbolId, | |
| 23 | +} from "@executor/ir/ids"; | |
| 23 | 24 | import type { |
| 24 | 25 | Capability, |
| 25 | 26 | CatalogSnapshotV1, |
| @@ -27,7 +28,9 @@ import type { · 1 unmodified line | ||
| 27 | 28 | Executable, |
| 28 | 29 | ShapeSymbol, |
| 29 | 30 | } from "@executor/ir/model"; |
| 30 | −import { LocalSourceArtifactMissingError } from "../../workspace-errors"; | |
| 31 | +import { | |
| 32 | + LocalSourceArtifactMissingError, | |
| 33 | +} from "../../scope-errors"; | |
| 31 | 34 | import { |
| 32 | 35 | createCatalogTypeProjector, |
| 33 | 36 | documentationComment, |
| @@ -36,21 +39,27 @@ import { · 2 unmodified lines | ||
| 36 | 39 | shapeAllowsOmittedArgs, |
| 37 | 40 | type CatalogTypeProjector, |
| 38 | 41 | } from "../catalog-typescript"; |
| 39 | −import { formatWithPrettier } from "../prettier-format"; | |
| 40 | 42 | import { |
| 41 | − RuntimeLocalWorkspaceService, | |
| 42 | − type RuntimeLocalWorkspaceState, | |
| 43 | −} from "../../workspace/runtime-context"; | |
| 44 | −import type { LocalSourceArtifact } from "../../source-artifacts"; | |
| 43 | + formatWithPrettier, | |
| 44 | +} from "../prettier-format"; | |
| 45 | +import { | |
| 46 | + RuntimeLocalScopeService, | |
| 47 | + type RuntimeLocalScopeState, | |
| 48 | +} from "../../scope/runtime-context"; | |
| 49 | +import type { | |
| 50 | + LocalSourceArtifact, | |
| 51 | +} from "../../source-artifacts"; | |
| 45 | 52 | import { |
| 46 | 53 | SourceArtifactStore, |
| 47 | 54 | type SourceArtifactStoreShape, |
| 48 | −} from "../../workspace/storage"; | |
| 55 | +} from "../../scope/storage"; | |
| 49 | 56 | import { |
| 50 | 57 | RuntimeSourceStoreService, |
| 51 | 58 | type RuntimeSourceStore, |
| 52 | 59 | } from "../../sources/source-store"; |
| 53 | −import { runtimeEffectError } from "../../effect-errors"; | |
| 60 | +import { | |
| 61 | + runtimeEffectError, | |
| 62 | +} from "../../effect-errors"; | |
| 54 | 63 | |
| 55 | 64 | type CatalogImportMetadata = CatalogSnapshotV1["import"]; |
| 56 | 65 | |
| @@ -644,7 +653,7 @@ const sourceRecordFromCatalogArtifact = (input: { · 587 unmodified lines | ||
| 644 | 653 | }; |
| 645 | 654 | }): StoredSourceRecord => ({ |
| 646 | 655 | id: input.source.id, |
| 647 | − workspaceId: input.source.workspaceId, | |
| 656 | + scopeId: input.source.scopeId, | |
| 648 | 657 | catalogId: input.artifact.catalogId, |
| 649 | 658 | catalogRevisionId: input.artifact.revision.id, |
| 650 | 659 | name: input.source.name, |
| @@ -663,23 +672,23 @@ const sourceRecordFromCatalogArtifact = (input: { · 12 unmodified lines | ||
| 663 | 672 | |
| 664 | 673 | type RuntimeSourceCatalogStoreShape = { |
| 665 | 674 | loadWorkspaceSourceCatalogs: (input: { |
| 666 | − workspaceId: WorkspaceId; | |
| 667 | − actorAccountId?: AccountId | null; | |
| 675 | + scopeId: ScopeId; | |
| 676 | + actorScopeId?: ScopeId | null; | |
| 668 | 677 | }) => Effect.Effect<readonly LoadedSourceCatalog[], Error, never>; |
| 669 | 678 | loadSourceWithCatalog: (input: { |
| 670 | − workspaceId: WorkspaceId; | |
| 679 | + scopeId: ScopeId; | |
| 671 | 680 | sourceId: Source["id"]; |
| 672 | − actorAccountId?: AccountId | null; | |
| 681 | + actorScopeId?: ScopeId | null; | |
| 673 | 682 | }) => Effect.Effect<LoadedSourceCatalog, Error | LocalSourceArtifactMissingError, never>; |
| 674 | 683 | loadWorkspaceSourceCatalogToolIndex: (input: { |
| 675 | − workspaceId: WorkspaceId; | |
| 676 | − actorAccountId?: AccountId | null; | |
| 684 | + scopeId: ScopeId; | |
| 685 | + actorScopeId?: ScopeId | null; | |
| 677 | 686 | includeSchemas: boolean; |
| 678 | 687 | }) => Effect.Effect<readonly LoadedSourceCatalogToolIndexEntry[], Error, never>; |
| 679 | 688 | loadWorkspaceSourceCatalogToolByPath: (input: { |
| 680 | − workspaceId: WorkspaceId; | |
| 689 | + scopeId: ScopeId; | |
| 681 | 690 | path: string; |
| 682 | − actorAccountId?: AccountId | null; | |
| 691 | + actorScopeId?: ScopeId | null; | |
| 683 | 692 | includeSchemas: boolean; |
| 684 | 693 | }) => Effect.Effect<LoadedSourceCatalogToolIndexEntry | null, Error, never>; |
| 685 | 694 | }; |
| @@ -691,25 +700,25 @@ export class RuntimeSourceCatalogStoreService extends Context.Tag( · 5 unmodified lines | ||
| 691 | 700 | )<RuntimeSourceCatalogStoreService, RuntimeSourceCatalogStoreShape>() {} |
| 692 | 701 | |
| 693 | 702 | type RuntimeSourceCatalogStoreDeps = { |
| 694 | − runtimeLocalWorkspace: RuntimeLocalWorkspaceState; | |
| 703 | + runtimeLocalScope: RuntimeLocalScopeState; | |
| 695 | 704 | sourceStore: RuntimeSourceStore; |
| 696 | 705 | sourceArtifactStore: SourceArtifactStoreShape; |
| 697 | 706 | }; |
| 698 | 707 | |
| 699 | 708 | type SourceCatalogRuntimeServices = |
| 700 | − | RuntimeLocalWorkspaceService | |
| 709 | + | RuntimeLocalScopeService | |
| 701 | 710 | | RuntimeSourceStoreService |
| 702 | 711 | | SourceArtifactStore; |
| 703 | 712 | |
| 704 | 713 | const ensureRuntimeCatalogWorkspace = ( |
| 705 | 714 | deps: RuntimeSourceCatalogStoreDeps, |
| 706 | − workspaceId: WorkspaceId, | |
| 715 | + scopeId: ScopeId, | |
| 707 | 716 | ) => |
| 708 | 717 | Effect.gen(function* () { |
| 709 | − if (deps.runtimeLocalWorkspace.installation.workspaceId !== workspaceId) { | |
| 718 | + if (deps.runtimeLocalScope.installation.scopeId !== scopeId) { | |
| 710 | 719 | return yield* Effect.fail( |
| 711 | 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 | 734 | const loadWorkspaceSourceCatalogsWithDeps = (deps: RuntimeSourceCatalogStoreDeps, input: { |
| 726 | − workspaceId: WorkspaceId; | |
| 727 | − actorAccountId?: AccountId | null; | |
| 735 | + scopeId: ScopeId; | |
| 736 | + actorScopeId?: ScopeId | null; | |
| 728 | 737 | }): Effect.Effect<readonly LoadedSourceCatalog[], Error, never> => |
| 729 | 738 | Effect.gen(function* () { |
| 730 | − yield* ensureRuntimeCatalogWorkspace(deps, input.workspaceId); | |
| 731 | − const sources = yield* deps.sourceStore.loadSourcesInWorkspace( | |
| 732 | − input.workspaceId, | |
| 739 | + yield* ensureRuntimeCatalogWorkspace(deps, input.scopeId); | |
| 740 | + const sources = yield* deps.sourceStore.loadSourcesInScope( | |
| 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 | 784 | const loadSourceWithCatalogWithDeps = (deps: RuntimeSourceCatalogStoreDeps, input: { |
| 776 | − workspaceId: WorkspaceId; | |
| 785 | + scopeId: ScopeId; | |
| 777 | 786 | sourceId: Source["id"]; |
| 778 | − actorAccountId?: AccountId | null; | |
| 787 | + actorScopeId?: ScopeId | null; | |
| 779 | 788 | }): Effect.Effect<LoadedSourceCatalog, Error | LocalSourceArtifactMissingError, never> => |
| 780 | 789 | Effect.gen(function* () { |
| 781 | − yield* ensureRuntimeCatalogWorkspace(deps, input.workspaceId); | |
| 790 | + yield* ensureRuntimeCatalogWorkspace(deps, input.scopeId); | |
| 782 | 791 | const source = yield* deps.sourceStore.loadSourceById({ |
| 783 | − workspaceId: input.workspaceId, | |
| 792 | + scopeId: input.scopeId, | |
| 784 | 793 | sourceId: input.sourceId, |
| 785 | − actorAccountId: input.actorAccountId, | |
| 794 | + actorScopeId: input.actorScopeId, | |
| 786 | 795 | }); |
| 787 | 796 | const artifact = yield* deps.sourceArtifactStore.read({ |
| 788 | 797 | sourceId: source.id, |
| @@ -819,17 +828,17 @@ const loadSourceWithCatalogWithDeps = (deps: RuntimeSourceCatalogStoreDeps, inpu · 30 unmodified lines | ||
| 819 | 828 | }); |
| 820 | 829 | |
| 821 | 830 | export const loadWorkspaceSourceCatalogs = (input: { |
| 822 | − workspaceId: WorkspaceId; | |
| 823 | − actorAccountId?: AccountId | null; | |
| 831 | + scopeId: ScopeId; | |
| 832 | + actorScopeId?: ScopeId | null; | |
| 824 | 833 | }): Effect.Effect<readonly LoadedSourceCatalog[], Error, SourceCatalogRuntimeServices> => |
| 825 | 834 | Effect.gen(function* () { |
| 826 | − const runtimeLocalWorkspace = yield* RuntimeLocalWorkspaceService; | |
| 835 | + const runtimeLocalScope = yield* RuntimeLocalScopeService; | |
| 827 | 836 | const sourceStore = yield* RuntimeSourceStoreService; |
| 828 | 837 | const sourceArtifactStore = yield* SourceArtifactStore; |
| 829 | 838 | |
| 830 | 839 | return yield* loadWorkspaceSourceCatalogsWithDeps( |
| 831 | 840 | { |
| 832 | − runtimeLocalWorkspace, | |
| 841 | + runtimeLocalScope, | |
| 833 | 842 | sourceStore, |
| 834 | 843 | sourceArtifactStore, |
| 835 | 844 | }, |
| @@ -838,22 +847,22 @@ export const loadWorkspaceSourceCatalogs = (input: { · 2 unmodified lines | ||
| 838 | 847 | }); |
| 839 | 848 | |
| 840 | 849 | export const loadSourceWithCatalog = (input: { |
| 841 | − workspaceId: WorkspaceId; | |
| 850 | + scopeId: ScopeId; | |
| 842 | 851 | sourceId: Source["id"]; |
| 843 | − actorAccountId?: AccountId | null; | |
| 852 | + actorScopeId?: ScopeId | null; | |
| 844 | 853 | }): Effect.Effect< |
| 845 | 854 | LoadedSourceCatalog, |
| 846 | 855 | Error | LocalSourceArtifactMissingError, |
| 847 | 856 | SourceCatalogRuntimeServices |
| 848 | 857 | > => |
| 849 | 858 | Effect.gen(function* () { |
| 850 | − const runtimeLocalWorkspace = yield* RuntimeLocalWorkspaceService; | |
| 859 | + const runtimeLocalScope = yield* RuntimeLocalScopeService; | |
| 851 | 860 | const sourceStore = yield* RuntimeSourceStoreService; |
| 852 | 861 | const sourceArtifactStore = yield* SourceArtifactStore; |
| 853 | 862 | |
| 854 | 863 | return yield* loadSourceWithCatalogWithDeps( |
| 855 | 864 | { |
| 856 | − runtimeLocalWorkspace, | |
| 865 | + runtimeLocalScope, | |
| 857 | 866 | sourceStore, |
| 858 | 867 | sourceArtifactStore, |
| 859 | 868 | }, |
| @@ -1096,8 +1105,8 @@ export const expandCatalogToolByPath = (input: { · 236 unmodified lines | ||
| 1096 | 1105 | ); |
| 1097 | 1106 | |
| 1098 | 1107 | export const loadWorkspaceSourceCatalogToolIndex = (input: { |
| 1099 | − workspaceId: WorkspaceId; | |
| 1100 | − actorAccountId?: AccountId | null; | |
| 1108 | + scopeId: ScopeId; | |
| 1109 | + actorScopeId?: ScopeId | null; | |
| 1101 | 1110 | includeSchemas: boolean; |
| 1102 | 1111 | }): Effect.Effect< |
| 1103 | 1112 | readonly LoadedSourceCatalogToolIndexEntry[], |
| @@ -1106,8 +1115,8 @@ export const loadWorkspaceSourceCatalogToolIndex = (input: { · 2 unmodified lines | ||
| 1106 | 1115 | > => |
| 1107 | 1116 | Effect.gen(function* () { |
| 1108 | 1117 | const catalogs = yield* loadWorkspaceSourceCatalogs({ |
| 1109 | − workspaceId: input.workspaceId, | |
| 1110 | − actorAccountId: input.actorAccountId, | |
| 1118 | + scopeId: input.scopeId, | |
| 1119 | + actorScopeId: input.actorScopeId, | |
| 1111 | 1120 | }); |
| 1112 | 1121 | const tools = yield* expandCatalogTools({ |
| 1113 | 1122 | catalogs, |
| @@ -1129,9 +1138,9 @@ export const loadWorkspaceSourceCatalogToolIndex = (input: { · 15 unmodified lines | ||
| 1129 | 1138 | }); |
| 1130 | 1139 | |
| 1131 | 1140 | export const loadWorkspaceSourceCatalogToolByPath = (input: { |
| 1132 | − workspaceId: WorkspaceId; | |
| 1141 | + scopeId: ScopeId; | |
| 1133 | 1142 | path: string; |
| 1134 | − actorAccountId?: AccountId | null; | |
| 1143 | + actorScopeId?: ScopeId | null; | |
| 1135 | 1144 | includeSchemas: boolean; |
| 1136 | 1145 | }): Effect.Effect< |
| 1137 | 1146 | LoadedSourceCatalogToolIndexEntry | null, |
| @@ -1140,8 +1149,8 @@ export const loadWorkspaceSourceCatalogToolByPath = (input: { · 2 unmodified lines | ||
| 1140 | 1149 | > => |
| 1141 | 1150 | Effect.gen(function* () { |
| 1142 | 1151 | const catalogs = yield* loadWorkspaceSourceCatalogs({ |
| 1143 | − workspaceId: input.workspaceId, | |
| 1144 | − actorAccountId: input.actorAccountId, | |
| 1152 | + scopeId: input.scopeId, | |
| 1153 | + actorScopeId: input.actorScopeId, | |
| 1145 | 1154 | }); |
| 1146 | 1155 | const tool = yield* expandCatalogToolByPath({ |
| 1147 | 1156 | catalogs, |
| @@ -1168,12 +1177,12 @@ export const loadWorkspaceSourceCatalogToolByPath = (input: { · 20 unmodified lines | ||
| 1168 | 1177 | export const RuntimeSourceCatalogStoreLive = Layer.effect( |
| 1169 | 1178 | RuntimeSourceCatalogStoreService, |
| 1170 | 1179 | Effect.gen(function* () { |
| 1171 | − const runtimeLocalWorkspace = yield* RuntimeLocalWorkspaceService; | |
| 1180 | + const runtimeLocalScope = yield* RuntimeLocalScopeService; | |
| 1172 | 1181 | const sourceStore = yield* RuntimeSourceStoreService; |
| 1173 | 1182 | const sourceArtifactStore = yield* SourceArtifactStore; |
| 1174 | 1183 | |
| 1175 | 1184 | const deps: RuntimeSourceCatalogStoreDeps = { |
| 1176 | − runtimeLocalWorkspace, | |
| 1185 | + runtimeLocalScope, | |
| 1177 | 1186 | sourceStore, |
| 1178 | 1187 | sourceArtifactStore, |
| 1179 | 1188 | }; |
| @@ -1185,13 +1194,13 @@ export const RuntimeSourceCatalogStoreLive = Layer.effect( · 5 unmodified lines | ||
| 1185 | 1194 | loadSourceWithCatalogWithDeps(deps, input), |
| 1186 | 1195 | loadWorkspaceSourceCatalogToolIndex: (input) => |
| 1187 | 1196 | loadWorkspaceSourceCatalogToolIndex(input).pipe( |
| 1188 | − Effect.provideService(RuntimeLocalWorkspaceService, runtimeLocalWorkspace), | |
| 1197 | + Effect.provideService(RuntimeLocalScopeService, runtimeLocalScope), | |
| 1189 | 1198 | Effect.provideService(RuntimeSourceStoreService, sourceStore), |
| 1190 | 1199 | Effect.provideService(SourceArtifactStore, sourceArtifactStore), |
| 1191 | 1200 | ), |
| 1192 | 1201 | loadWorkspaceSourceCatalogToolByPath: (input) => |
| 1193 | 1202 | loadWorkspaceSourceCatalogToolByPath(input).pipe( |
| 1194 | − Effect.provideService(RuntimeLocalWorkspaceService, runtimeLocalWorkspace), | |
| 1203 | + Effect.provideService(RuntimeLocalScopeService, runtimeLocalScope), | |
| 1195 | 1204 | Effect.provideService(RuntimeSourceStoreService, sourceStore), |
| 1196 | 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 | 11 | import { |
| 6 | 12 | buildGraphqlToolPresentation, |
| 7 | 13 | compileGraphqlToolDefinitions, |
| 8 | 14 | type GraphqlToolManifest, |
| 9 | 15 | } from "@executor/source-graphql"; |
| 10 | −import { createGoogleDiscoveryCatalogSnapshot } from "@executor/source-google-discovery"; | |
| 11 | −import { createGraphqlCatalogSnapshot } from "@executor/source-graphql"; | |
| 12 | −import { createMcpCatalogSnapshot } from "@executor/source-mcp"; | |
| 13 | −import { createOpenApiCatalogSnapshot } from "@executor/source-openapi"; | |
| 16 | +import { | |
| 17 | + createGoogleDiscoveryCatalogSnapshot, | |
| 18 | +} from "@executor/source-google-discovery"; | |
| 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 | 29 | const baseSource: Source = { |
| 16 | 30 | id: "src_calendar" as Source["id"], |
| 17 | − workspaceId: "ws_test" as Source["workspaceId"], | |
| 31 | + scopeId: "ws_test" as Source["scopeId"], | |
| 18 | 32 | name: "Calendar", |
| 19 | 33 | kind: "openapi", |
| 20 | 34 | endpoint: "https://api.example.test", |
| @@ -1,26 +1,28 @@ | ||
| 1 | 1 | import type { |
| 2 | − AccountId, | |
| 2 | + ScopeId, | |
| 3 | 3 | Source, |
| 4 | 4 | SourceStatus, |
| 5 | 5 | } from "#schema"; |
| 6 | −import type { McpToolManifest } from "@executor/source-mcp"; | |
| 6 | +import type { | |
| 7 | + McpToolManifest, | |
| 8 | +} from "@executor/source-mcp"; | |
| 7 | 9 | import * as Context from "effect/Context"; |
| 8 | 10 | import * as Effect from "effect/Effect"; |
| 9 | 11 | import * as Layer from "effect/Layer"; |
| 10 | 12 | |
| 11 | 13 | import { |
| 12 | − RuntimeLocalWorkspaceService, | |
| 13 | − type RuntimeLocalWorkspaceState, | |
| 14 | −} from "../../workspace/runtime-context"; | |
| 14 | + RuntimeLocalScopeService, | |
| 15 | + type RuntimeLocalScopeState, | |
| 16 | +} from "../../scope/runtime-context"; | |
| 15 | 17 | import { |
| 16 | 18 | SourceArtifactStore, |
| 17 | 19 | type SourceArtifactStoreShape, |
| 18 | − WorkspaceStateStore, | |
| 19 | − type WorkspaceStateStoreShape, | |
| 20 | −} from "../../workspace/storage"; | |
| 20 | + ScopeStateStore, | |
| 21 | + type ScopeStateStoreShape, | |
| 22 | +} from "../../scope/storage"; | |
| 21 | 23 | import { |
| 22 | − type LocalWorkspaceState, | |
| 23 | −} from "../../workspace-state"; | |
| 24 | + type LocalScopeState, | |
| 25 | +} from "../../scope-state"; | |
| 24 | 26 | import { |
| 25 | 27 | RuntimeSourceAuthMaterialService, |
| 26 | 28 | } from "../../auth/source-auth-material"; |
| @@ -30,13 +32,19 @@ import { · 3 unmodified lines | ||
| 30 | 32 | import { |
| 31 | 33 | catalogSyncResultFromMcpManifest, |
| 32 | 34 | } from "@executor/source-mcp"; |
| 33 | −import { SecretMaterialResolverService } from "../../workspace/secret-material-providers"; | |
| 34 | −import { snapshotFromSourceCatalogSyncResult } from "@executor/source-core"; | |
| 35 | +import { | |
| 36 | + SecretMaterialResolverService, | |
| 37 | +} from "../../scope/secret-material-providers"; | |
| 38 | +import { | |
| 39 | + snapshotFromSourceCatalogSyncResult, | |
| 40 | +} from "@executor/source-core"; | |
| 35 | 41 | import { |
| 36 | 42 | SourceTypeDeclarationsRefresherService, |
| 37 | 43 | type SourceTypeDeclarationsRefresherShape, |
| 38 | 44 | } from "./type-declarations"; |
| 39 | −import { runtimeEffectError } from "../../effect-errors"; | |
| 45 | +import { | |
| 46 | + runtimeEffectError, | |
| 47 | +} from "../../effect-errors"; | |
| 40 | 48 | |
| 41 | 49 | const shouldIndexSource = (source: Source): boolean => |
| 42 | 50 | source.enabled |
| @@ -44,8 +52,8 @@ const shouldIndexSource = (source: Source): boolean => · 1 unmodified line | ||
| 44 | 52 | && getSourceAdapterForSource(source).catalogKind !== "internal"; |
| 45 | 53 | |
| 46 | 54 | type RuntimeSourceCatalogSyncDeps = { |
| 47 | − runtimeLocalWorkspace: RuntimeLocalWorkspaceState; | |
| 48 | − workspaceStateStore: WorkspaceStateStoreShape; | |
| 55 | + runtimeLocalScope: RuntimeLocalScopeState; | |
| 56 | + scopeStateStore: ScopeStateStoreShape; | |
| 49 | 57 | sourceArtifactStore: SourceArtifactStoreShape; |
| 50 | 58 | sourceTypeDeclarationsRefresher: SourceTypeDeclarationsRefresherShape; |
| 51 | 59 | resolveSecretMaterial: Effect.Effect.Success<typeof SecretMaterialResolverService>; |
| @@ -53,8 +61,8 @@ type RuntimeSourceCatalogSyncDeps = { · 1 unmodified line | ||
| 53 | 61 | }; |
| 54 | 62 | |
| 55 | 63 | type SourceCatalogSyncServices = |
| 56 | − | RuntimeLocalWorkspaceService | |
| 57 | − | WorkspaceStateStore | |
| 64 | + | RuntimeLocalScopeService | |
| 65 | + | ScopeStateStore | |
| 58 | 66 | | SourceArtifactStore |
| 59 | 67 | | SourceTypeDeclarationsRefresherService |
| 60 | 68 | | RuntimeSourceAuthMaterialService |
| @@ -63,7 +71,7 @@ type SourceCatalogSyncServices = · 2 unmodified lines | ||
| 63 | 71 | export type RuntimeSourceCatalogSyncShape = { |
| 64 | 72 | sync: (input: { |
| 65 | 73 | source: Source; |
| 66 | − actorAccountId?: AccountId | null; | |
| 74 | + actorScopeId?: ScopeId | null; | |
| 67 | 75 | }) => Effect.Effect<void, Error, never>; |
| 68 | 76 | persistMcpCatalogSnapshotFromManifest: (input: { |
| 69 | 77 | source: Source; |
| @@ -77,13 +85,13 @@ export class RuntimeSourceCatalogSyncService extends Context.Tag( · 7 unmodified lines | ||
| 77 | 85 | |
| 78 | 86 | const ensureRuntimeCatalogSyncWorkspace = ( |
| 79 | 87 | deps: RuntimeSourceCatalogSyncDeps, |
| 80 | − workspaceId: Source["workspaceId"], | |
| 88 | + scopeId: Source["scopeId"], | |
| 81 | 89 | ) => |
| 82 | 90 | Effect.gen(function* () { |
| 83 | − if (deps.runtimeLocalWorkspace.installation.workspaceId !== workspaceId) { | |
| 91 | + if (deps.runtimeLocalScope.installation.scopeId !== scopeId) { | |
| 84 | 92 | return yield* Effect.fail( |
| 85 | 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 | 101 | deps: RuntimeSourceCatalogSyncDeps, |
| 94 | 102 | input: { |
| 95 | 103 | source: Source; |
| 96 | − actorAccountId?: AccountId | null; | |
| 104 | + actorScopeId?: ScopeId | null; | |
| 97 | 105 | }, |
| 98 | 106 | ): Effect.Effect<void, Error, never> => |
| 99 | 107 | Effect.gen(function* () { |
| 100 | − yield* ensureRuntimeCatalogSyncWorkspace(deps, input.source.workspaceId); | |
| 108 | + yield* ensureRuntimeCatalogSyncWorkspace(deps, input.source.scopeId); | |
| 101 | 109 | |
| 102 | 110 | if (!shouldIndexSource(input.source)) { |
| 103 | − const state = yield* deps.workspaceStateStore.load(); | |
| 111 | + const state = yield* deps.scopeStateStore.load(); | |
| 104 | 112 | const existingSourceState = state.sources[input.source.id]; |
| 105 | − const nextState: LocalWorkspaceState = { | |
| 113 | + const nextState: LocalScopeState = { | |
| 106 | 114 | ...state, |
| 107 | 115 | sources: { |
| 108 | 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 | 127 | state: nextState, |
| 120 | 128 | }); |
| 121 | 129 | yield* deps.sourceTypeDeclarationsRefresher.refreshSourceInBackground({ |
| @@ -133,7 +141,7 @@ const syncSourceCatalogWithDeps = ( · 11 unmodified lines | ||
| 133 | 141 | deps.sourceAuthMaterialService.resolve({ |
| 134 | 142 | source: input.source, |
| 135 | 143 | slot, |
| 136 | − actorAccountId: input.actorAccountId, | |
| 144 | + actorScopeId: input.actorScopeId, | |
| 137 | 145 | }), |
| 138 | 146 | }); |
| 139 | 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 | 157 | const existingSourceState = state.sources[input.source.id]; |
| 150 | − const nextState: LocalWorkspaceState = { | |
| 158 | + const nextState: LocalScopeState = { | |
| 151 | 159 | ...state, |
| 152 | 160 | sources: { |
| 153 | 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 | 172 | state: nextState, |
| 165 | 173 | }); |
| 166 | 174 | |
| @@ -187,7 +195,7 @@ const persistMcpCatalogSnapshotFromManifestWithDeps = ( · 20 unmodified lines | ||
| 187 | 195 | }, |
| 188 | 196 | ): Effect.Effect<void, Error, never> => |
| 189 | 197 | Effect.gen(function* () { |
| 190 | − yield* ensureRuntimeCatalogSyncWorkspace(deps, input.source.workspaceId); | |
| 198 | + yield* ensureRuntimeCatalogSyncWorkspace(deps, input.source.scopeId); | |
| 191 | 199 | const syncResult = catalogSyncResultFromMcpManifest({ |
| 192 | 200 | source: input.source, |
| 193 | 201 | endpoint: input.source.endpoint, |
| @@ -211,11 +219,11 @@ const persistMcpCatalogSnapshotFromManifestWithDeps = ( · 17 unmodified lines | ||
| 211 | 219 | |
| 212 | 220 | export const syncSourceCatalog = (input: { |
| 213 | 221 | source: Source; |
| 214 | − actorAccountId?: AccountId | null; | |
| 222 | + actorScopeId?: ScopeId | null; | |
| 215 | 223 | }): Effect.Effect<void, Error, SourceCatalogSyncServices> => |
| 216 | 224 | Effect.gen(function* () { |
| 217 | − const runtimeLocalWorkspace = yield* RuntimeLocalWorkspaceService; | |
| 218 | − const workspaceStateStore = yield* WorkspaceStateStore; | |
| 225 | + const runtimeLocalScope = yield* RuntimeLocalScopeService; | |
| 226 | + const scopeStateStore = yield* ScopeStateStore; | |
| 219 | 227 | const sourceArtifactStore = yield* SourceArtifactStore; |
| 220 | 228 | const sourceTypeDeclarationsRefresher = |
| 221 | 229 | yield* SourceTypeDeclarationsRefresherService; |
| @@ -224,8 +232,8 @@ export const syncSourceCatalog = (input: { · 2 unmodified lines | ||
| 224 | 232 | |
| 225 | 233 | return yield* syncSourceCatalogWithDeps( |
| 226 | 234 | { |
| 227 | − runtimeLocalWorkspace, | |
| 228 | − workspaceStateStore, | |
| 235 | + runtimeLocalScope, | |
| 236 | + scopeStateStore, | |
| 229 | 237 | sourceArtifactStore, |
| 230 | 238 | sourceTypeDeclarationsRefresher, |
| 231 | 239 | resolveSecretMaterial, |
| @@ -233,7 +241,7 @@ export const syncSourceCatalog = (input: { · 1 unmodified line | ||
| 233 | 241 | }, |
| 234 | 242 | { |
| 235 | 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 | 251 | manifest: McpToolManifest; |
| 244 | 252 | }): Effect.Effect<void, Error, SourceCatalogSyncServices> => |
| 245 | 253 | Effect.gen(function* () { |
| 246 | − const runtimeLocalWorkspace = yield* RuntimeLocalWorkspaceService; | |
| 247 | − const workspaceStateStore = yield* WorkspaceStateStore; | |
| 254 | + const runtimeLocalScope = yield* RuntimeLocalScopeService; | |
| 255 | + const scopeStateStore = yield* ScopeStateStore; | |
| 248 | 256 | const sourceArtifactStore = yield* SourceArtifactStore; |
| 249 | 257 | const sourceTypeDeclarationsRefresher = |
| 250 | 258 | yield* SourceTypeDeclarationsRefresherService; |
| @@ -253,8 +261,8 @@ export const persistMcpCatalogSnapshotFromManifest = (input: { · 2 unmodified lines | ||
| 253 | 261 | |
| 254 | 262 | return yield* persistMcpCatalogSnapshotFromManifestWithDeps( |
| 255 | 263 | { |
| 256 | − runtimeLocalWorkspace, | |
| 257 | − workspaceStateStore, | |
| 264 | + runtimeLocalScope, | |
| 265 | + scopeStateStore, | |
| 258 | 266 | sourceArtifactStore, |
| 259 | 267 | sourceTypeDeclarationsRefresher, |
| 260 | 268 | resolveSecretMaterial, |
| @@ -267,8 +275,8 @@ export const persistMcpCatalogSnapshotFromManifest = (input: { · 6 unmodified lines | ||
| 267 | 275 | export const RuntimeSourceCatalogSyncLive = Layer.effect( |
| 268 | 276 | RuntimeSourceCatalogSyncService, |
| 269 | 277 | Effect.gen(function* () { |
| 270 | − const runtimeLocalWorkspace = yield* RuntimeLocalWorkspaceService; | |
| 271 | − const workspaceStateStore = yield* WorkspaceStateStore; | |
| 278 | + const runtimeLocalScope = yield* RuntimeLocalScopeService; | |
| 279 | + const scopeStateStore = yield* ScopeStateStore; | |
| 272 | 280 | const sourceArtifactStore = yield* SourceArtifactStore; |
| 273 | 281 | const sourceTypeDeclarationsRefresher = |
| 274 | 282 | yield* SourceTypeDeclarationsRefresherService; |
| @@ -276,8 +284,8 @@ export const RuntimeSourceCatalogSyncLive = Layer.effect( · 1 unmodified line | ||
| 276 | 284 | const sourceAuthMaterialService = yield* RuntimeSourceAuthMaterialService; |
| 277 | 285 | |
| 278 | 286 | const deps: RuntimeSourceCatalogSyncDeps = { |
| 279 | − runtimeLocalWorkspace, | |
| 280 | − workspaceStateStore, | |
| 287 | + runtimeLocalScope, | |
| 288 | + scopeStateStore, | |
| 281 | 289 | sourceArtifactStore, |
| 282 | 290 | sourceTypeDeclarationsRefresher, |
| 283 | 291 | resolveSecretMaterial, |
| @@ -1,5 +1,9 @@ | ||
| 1 | −import type { Source } from "#schema"; | |
| 2 | −import type { CatalogSnapshotV1 } from "@executor/ir/model"; | |
| 1 | +import type { | |
| 2 | + Source, | |
| 3 | +} from "#schema"; | |
| 4 | +import type { | |
| 5 | + CatalogSnapshotV1, | |
| 6 | +} from "@executor/ir/model"; | |
| 3 | 7 | import * as Context from "effect/Context"; |
| 4 | 8 | import * as Effect from "effect/Effect"; |
| 5 | 9 | |
| @@ -1,16 +1,36 @@ | ||
| 1 | −import { tmpdir } from "node:os"; | |
| 2 | −import { join } from "node:path"; | |
| 3 | −import { FileSystem } from "@effect/platform"; | |
| 4 | −import { NodeFileSystem } from "@effect/platform-node"; | |
| 5 | −import { describe, expect, it } from "@effect/vitest"; | |
| 1 | +import { | |
| 2 | + tmpdir, | |
| 3 | +} from "node:os"; | |
| 4 | +import { | |
| 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 | 18 | import * as Effect from "effect/Effect"; |
| 7 | 19 | import * as Schema from "effect/Schema"; |
| 8 | 20 | |
| 9 | −import { makeToolInvokerFromTools } from "@executor/codemode-core"; | |
| 10 | −import { makeDenoSubprocessExecutor } from "@executor/runtime-deno-subprocess"; | |
| 21 | +import { | |
| 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"; | |
| 13 | −import { withExecutorApiClient } from "./test-http-client"; | |
| 28 | +import { | |
| 29 | + createLocalExecutorRuntime as createExecutorRuntime, | |
| 30 | +} from "../../../../sdk-file/src/index"; | |
| 31 | +import { | |
| 32 | + withExecutorApiClient, | |
| 33 | +} from "./test-http-client"; | |
| 14 | 34 | |
| 15 | 35 | const makeExecutionResolver = () => { |
| 16 | 36 | const toolInvoker = makeToolInvokerFromTools({ |
| @@ -41,22 +61,22 @@ const makeExecutionResolver = () => { · 24 unmodified lines | ||
| 41 | 61 | const makeRuntime = Effect.acquireRelease( |
| 42 | 62 | Effect.gen(function* () { |
| 43 | 63 | const fs = yield* FileSystem.FileSystem; |
| 44 | − const workspaceRoot = yield* fs.makeTempDirectory({ | |
| 64 | + const scopeRoot = yield* fs.makeTempDirectory({ | |
| 45 | 65 | directory: tmpdir(), |
| 46 | 66 | prefix: "executor-execution-http-", |
| 47 | 67 | }); |
| 48 | 68 | |
| 49 | 69 | return { |
| 50 | − workspaceRoot, | |
| 51 | − homeConfigPath: join(workspaceRoot, ".executor-home.jsonc"), | |
| 52 | − homeStateDirectory: join(workspaceRoot, ".executor-home-state"), | |
| 70 | + scopeRoot, | |
| 71 | + homeConfigPath: join(scopeRoot, ".executor-home.jsonc"), | |
| 72 | + homeStateDirectory: join(scopeRoot, ".executor-home-state"), | |
| 53 | 73 | }; |
| 54 | 74 | }).pipe( |
| 55 | 75 | Effect.provide(NodeFileSystem.layer), |
| 56 | − Effect.flatMap(({ workspaceRoot, homeConfigPath, homeStateDirectory }) => | |
| 76 | + Effect.flatMap(({ scopeRoot, homeConfigPath, homeStateDirectory }) => | |
| 57 | 77 | createExecutorRuntime({ |
| 58 | 78 | localDataDir: ":memory:", |
| 59 | − workspaceRoot, | |
| 79 | + workspaceRoot: scopeRoot, | |
| 60 | 80 | homeConfigPath, |
| 61 | 81 | homeStateDirectory, |
| 62 | 82 | executionResolver: makeExecutionResolver(), |
| @@ -75,12 +95,12 @@ describe("execution-http", () => { · 12 unmodified lines | ||
| 75 | 95 | const createExecution = yield* withExecutorApiClient( |
| 76 | 96 | { |
| 77 | 97 | runtime, |
| 78 | − accountId: installation.accountId, | |
| 98 | + actorScopeId: installation.actorScopeId, | |
| 79 | 99 | }, |
| 80 | 100 | (client) => |
| 81 | 101 | client.executions.create({ |
| 82 | 102 | path: { |
| 83 | − workspaceId: installation.workspaceId, | |
| 103 | + scopeId: installation.scopeId, | |
| 84 | 104 | }, |
| 85 | 105 | payload: { |
| 86 | 106 | code: "return await tools.math.add({ a: 20, b: 22 });", |
| @@ -95,12 +115,12 @@ describe("execution-http", () => { · 8 unmodified lines | ||
| 95 | 115 | const getExecution = yield* withExecutorApiClient( |
| 96 | 116 | { |
| 97 | 117 | runtime, |
| 98 | − accountId: installation.accountId, | |
| 118 | + actorScopeId: installation.actorScopeId, | |
| 99 | 119 | }, |
| 100 | 120 | (client) => |
| 101 | 121 | client.executions.get({ |
| 102 | 122 | path: { |
| 103 | − workspaceId: installation.workspaceId, | |
| 123 | + scopeId: installation.scopeId, | |
| 104 | 124 | executionId: createExecution.execution.id, |
| 105 | 125 | }, |
| 106 | 126 | }), |
| @@ -1,11 +1,24 @@ | ||
| 1 | −import type { AccountId, Source } from "#schema"; | |
| 2 | −import type { OnElicitation } from "@executor/codemode-core"; | |
| 1 | +import type { | |
| 2 | + ScopeId, | |
| 3 | + Source, | |
| 4 | +} from "#schema"; | |
| 5 | +import type { | |
| 6 | + OnElicitation, | |
| 7 | +} from "@executor/codemode-core"; | |
| 3 | 8 | import * as Effect from "effect/Effect"; |
| 4 | 9 | |
| 5 | −import type { LoadedSourceCatalogToolIndexEntry } from "../catalog/source/runtime"; | |
| 6 | −import type { ResolvedSourceAuthMaterial } from "../auth/source-auth-material"; | |
| 7 | −import { getSourceAdapter } from "../sources/source-adapters"; | |
| 8 | −import { runtimeEffectError } from "../effect-errors"; | |
| 10 | +import type { | |
| 11 | + LoadedSourceCatalogToolIndexEntry, | |
| 12 | +} from "../catalog/source/runtime"; | |
| 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 | 23 | export const invocationDescriptorFromTool = (input: { |
| 11 | 24 | tool: LoadedSourceCatalogToolIndexEntry; |
| @@ -39,8 +52,8 @@ export const invocationDescriptorFromTool = (input: { · 27 unmodified lines | ||
| 39 | 52 | }); |
| 40 | 53 | |
| 41 | 54 | export const invokeIrTool = (input: { |
| 42 | − workspaceId: Source["workspaceId"]; | |
| 43 | − accountId: AccountId; | |
| 55 | + scopeId: Source["scopeId"]; | |
| 56 | + actorScopeId: ScopeId; | |
| 44 | 57 | tool: LoadedSourceCatalogToolIndexEntry; |
| 45 | 58 | auth: ResolvedSourceAuthMaterial; |
| 46 | 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 | 11 | describe("live-execution", () => { |
| 6 | 12 | it("redacts secret refs from persisted interaction responses", () => { |
| @@ -2,7 +2,9 @@ import type { · 1 unmodified line | ||
| 2 | 2 | ElicitationResponse, |
| 3 | 3 | OnElicitation, |
| 4 | 4 | } from "@executor/codemode-core"; |
| 5 | −import { clearMcpConnectionPoolRun } from "@executor/source-mcp"; | |
| 5 | +import { | |
| 6 | + clearMcpConnectionPoolRun, | |
| 7 | +} from "@executor/source-mcp"; | |
| 6 | 8 | import { |
| 7 | 9 | ExecutionInteractionIdSchema, |
| 8 | 10 | type Execution, |
| @@ -13,7 +15,9 @@ import * as Deferred from "effect/Deferred"; · 4 unmodified lines | ||
| 13 | 15 | import * as Effect from "effect/Effect"; |
| 14 | 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 | 22 | type VisibleExecutionState = |
| 19 | 23 | | "running" |
| @@ -1,29 +1,67 @@ | ||
| 1 | −import { randomUUID } from "node:crypto"; | |
| 2 | − | |
| 3 | −import { createMcpExpressApp } from "@modelcontextprotocol/sdk/server/express.js"; | |
| 4 | −import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; | |
| 5 | −import { Client } from "@modelcontextprotocol/sdk/client/index.js"; | |
| 6 | −import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js"; | |
| 7 | −import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js"; | |
| 8 | −import { tmpdir } from "node:os"; | |
| 9 | −import { join } from "node:path"; | |
| 10 | −import { FileSystem } from "@effect/platform"; | |
| 11 | −import { NodeFileSystem } from "@effect/platform-node"; | |
| 12 | −import { describe, expect, it } from "@effect/vitest"; | |
| 13 | −import { assertTrue } from "@effect/vitest/utils"; | |
| 1 | +import { | |
| 2 | + randomUUID, | |
| 3 | +} from "node:crypto"; | |
| 4 | + | |
| 5 | +import { | |
| 6 | + createMcpExpressApp, | |
| 7 | +} from "@modelcontextprotocol/sdk/server/express.js"; | |
| 8 | +import { | |
| 9 | + McpServer, | |
| 10 | +} from "@modelcontextprotocol/sdk/server/mcp.js"; | |
| 11 | +import { | |
| 12 | + Client, | |
| 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 | 40 | import * as Effect from "effect/Effect"; |
| 15 | 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"; | |
| 19 | −import { discoverMcpToolsFromConnector } from "@executor/source-mcp"; | |
| 20 | −import { makeDenoSubprocessExecutor } from "@executor/runtime-deno-subprocess"; | |
| 46 | +import { | |
| 47 | + makeToolInvokerFromTools, | |
| 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 | 56 | import { |
| 23 | 57 | type ResolveExecutionEnvironment, |
| 24 | 58 | } from "../index"; |
| 25 | −import { createLocalExecutorRuntime as createExecutorRuntime } from "../../../../sdk-file/src/index"; | |
| 26 | −import { withExecutorApiClient } from "./test-http-client"; | |
| 59 | +import { | |
| 60 | + createLocalExecutorRuntime as createExecutorRuntime, | |
| 61 | +} from "../../../../sdk-file/src/index"; | |
| 62 | +import { | |
| 63 | + withExecutorApiClient, | |
| 64 | +} from "./test-http-client"; | |
| 27 | 65 | |
| 28 | 66 | type McpFormServer = { |
| 29 | 67 | endpoint: string; |
| @@ -290,16 +328,16 @@ describe("execution-mcp-resume", () => { · 260 unmodified lines | ||
| 290 | 328 | Effect.gen(function* () { |
| 291 | 329 | const mcpServer = yield* makeFormElicitationServer; |
| 292 | 330 | const fs = yield* FileSystem.FileSystem; |
| 293 | − const workspaceRoot = yield* fs.makeTempDirectory({ | |
| 331 | + const scopeRoot = yield* fs.makeTempDirectory({ | |
| 294 | 332 | directory: tmpdir(), |
| 295 | 333 | prefix: "executor-execution-mcp-resume-", |
| 296 | 334 | }); |
| 297 | 335 | const runtime = yield* Effect.acquireRelease( |
| 298 | 336 | createExecutorRuntime({ |
| 299 | 337 | localDataDir: ":memory:", |
| 300 | − workspaceRoot, | |
| 301 | − homeConfigPath: join(workspaceRoot, ".executor-home.jsonc"), | |
| 302 | − homeStateDirectory: join(workspaceRoot, ".executor-home-state"), | |
| 338 | + workspaceRoot: scopeRoot, | |
| 339 | + homeConfigPath: join(scopeRoot, ".executor-home.jsonc"), | |
| 340 | + homeStateDirectory: join(scopeRoot, ".executor-home-state"), | |
| 303 | 341 | executionResolver: makeMcpExecutionResolver(mcpServer.endpoint), |
| 304 | 342 | }), |
| 305 | 343 | (runtime) => Effect.promise(() => runtime.close()).pipe(Effect.orDie), |
| @@ -310,12 +348,12 @@ describe("execution-mcp-resume", () => { · 4 unmodified lines | ||
| 310 | 348 | const created = yield* withExecutorApiClient( |
| 311 | 349 | { |
| 312 | 350 | runtime, |
| 313 | − accountId: installation.accountId, | |
| 351 | + actorScopeId: installation.actorScopeId, | |
| 314 | 352 | }, |
| 315 | 353 | (client) => |
| 316 | 354 | client.executions.create({ |
| 317 | 355 | path: { |
| 318 | − workspaceId: installation.workspaceId, | |
| 356 | + scopeId: installation.scopeId, | |
| 319 | 357 | }, |
| 320 | 358 | payload: { |
| 321 | 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 | 382 | const resumed = yield* withExecutorApiClient( |
| 345 | 383 | { |
| 346 | 384 | runtime, |
| 347 | − accountId: installation.accountId, | |
| 385 | + actorScopeId: installation.actorScopeId, | |
| 348 | 386 | }, |
| 349 | 387 | (client) => |
| 350 | 388 | client.executions.resume({ |
| 351 | 389 | path: { |
| 352 | − workspaceId: installation.workspaceId, | |
| 390 | + scopeId: installation.scopeId, | |
| 353 | 391 | executionId: created.execution.id, |
| 354 | 392 | }, |
| 355 | 393 | payload: { |
| @@ -1,20 +1,36 @@ | ||
| 1 | −import { tmpdir } from "node:os"; | |
| 2 | −import { join } from "node:path"; | |
| 3 | −import { FileSystem } from "@effect/platform"; | |
| 4 | −import { NodeFileSystem } from "@effect/platform-node"; | |
| 5 | −import { describe, expect, it } from "@effect/vitest"; | |
| 1 | +import { | |
| 2 | + tmpdir, | |
| 3 | +} from "node:os"; | |
| 4 | +import { | |
| 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 | 18 | import * as Effect from "effect/Effect"; |
| 7 | 19 | |
| 8 | −import { createLocalExecutorRuntime as createExecutorRuntime } from "../../../../sdk-file/src/index"; | |
| 9 | −import { withExecutorApiClient } from "./test-http-client"; | |
| 20 | +import { | |
| 21 | + createLocalExecutorRuntime as createExecutorRuntime, | |
| 22 | +} from "../../../../sdk-file/src/index"; | |
| 23 | +import { | |
| 24 | + withExecutorApiClient, | |
| 25 | +} from "./test-http-client"; | |
| 10 | 26 | |
| 11 | 27 | const writeProjectConfig = ( |
| 12 | − workspaceRoot: string, | |
| 28 | + scopeRoot: string, | |
| 13 | 29 | config: Record<string, unknown>, |
| 14 | 30 | ) => |
| 15 | 31 | Effect.gen(function* () { |
| 16 | 32 | const fs = yield* FileSystem.FileSystem; |
| 17 | − const configDirectory = join(workspaceRoot, ".executor"); | |
| 33 | + const configDirectory = join(scopeRoot, ".executor"); | |
| 18 | 34 | yield* fs.makeDirectory(configDirectory, { recursive: true }); |
| 19 | 35 | yield* fs.writeFileString( |
| 20 | 36 | join(configDirectory, "executor.jsonc"), |
| @@ -26,16 +42,16 @@ const makeRuntime = (config: Record<string, unknown>) => { · 5 unmodified lines | ||
| 26 | 42 | return Effect.acquireRelease( |
| 27 | 43 | Effect.gen(function* () { |
| 28 | 44 | const fs = yield* FileSystem.FileSystem; |
| 29 | − const workspaceRoot = yield* fs.makeTempDirectory({ | |
| 45 | + const scopeRoot = yield* fs.makeTempDirectory({ | |
| 30 | 46 | directory: tmpdir(), |
| 31 | 47 | prefix: "executor-runtime-config-", |
| 32 | 48 | }); |
| 33 | − yield* writeProjectConfig(workspaceRoot, config); | |
| 49 | + yield* writeProjectConfig(scopeRoot, config); | |
| 34 | 50 | |
| 35 | 51 | return yield* createExecutorRuntime({ |
| 36 | − workspaceRoot, | |
| 37 | − homeConfigPath: join(workspaceRoot, ".executor-home.jsonc"), | |
| 38 | − homeStateDirectory: join(workspaceRoot, ".executor-home-state"), | |
| 52 | + workspaceRoot: scopeRoot, | |
| 53 | + homeConfigPath: join(scopeRoot, ".executor-home.jsonc"), | |
| 54 | + homeStateDirectory: join(scopeRoot, ".executor-home-state"), | |
| 39 | 55 | }); |
| 40 | 56 | }).pipe(Effect.provide(NodeFileSystem.layer)), |
| 41 | 57 | (runtime) => Effect.promise(() => runtime.close()).pipe(Effect.orDie), |
| @@ -53,12 +69,12 @@ describe("execution runtime config", () => { · 11 unmodified lines | ||
| 53 | 69 | const execution = yield* withExecutorApiClient( |
| 54 | 70 | { |
| 55 | 71 | runtime, |
| 56 | − accountId: installation.accountId, | |
| 72 | + actorScopeId: installation.actorScopeId, | |
| 57 | 73 | }, |
| 58 | 74 | (client) => |
| 59 | 75 | client.executions.create({ |
| 60 | 76 | path: { |
| 61 | − workspaceId: installation.workspaceId, | |
| 77 | + scopeId: installation.scopeId, | |
| 62 | 78 | }, |
| 63 | 79 | payload: { |
| 64 | 80 | code: 'await fetch("https://example.com"); return 1;', |
| @@ -85,12 +101,12 @@ describe("execution runtime config", () => { · 20 unmodified lines | ||
| 85 | 101 | const execution = yield* withExecutorApiClient( |
| 86 | 102 | { |
| 87 | 103 | runtime, |
| 88 | − accountId: installation.accountId, | |
| 104 | + actorScopeId: installation.actorScopeId, | |
| 89 | 105 | }, |
| 90 | 106 | (client) => |
| 91 | 107 | client.executions.create({ |
| 92 | 108 | path: { |
| 93 | − workspaceId: installation.workspaceId, | |
| 109 | + scopeId: installation.scopeId, | |
| 94 | 110 | }, |
| 95 | 111 | payload: { |
| 96 | 112 | code: 'await fetch("https://example.com"); return 1;', |
| @@ -117,12 +133,12 @@ describe("execution runtime config", () => { · 20 unmodified lines | ||
| 117 | 133 | const execution = yield* withExecutorApiClient( |
| 118 | 134 | { |
| 119 | 135 | runtime, |
| 120 | − accountId: installation.accountId, | |
| 136 | + actorScopeId: installation.actorScopeId, | |
| 121 | 137 | }, |
| 122 | 138 | (client) => |
| 123 | 139 | client.executions.create({ |
| 124 | 140 | path: { |
| 125 | − workspaceId: installation.workspaceId, | |
| 141 | + scopeId: installation.scopeId, | |
| 126 | 142 | }, |
| 127 | 143 | payload: { |
| 128 | 144 | code: 'return typeof Deno !== "undefined";', |
| @@ -1,8 +1,19 @@ | ||
| 1 | −import type { CodeExecutor } from "@executor/codemode-core"; | |
| 2 | −import { makeDenoSubprocessExecutor } from "@executor/runtime-deno-subprocess"; | |
| 3 | −import { makeQuickJsExecutor } from "@executor/runtime-quickjs"; | |
| 4 | −import { makeSesExecutor } from "@executor/runtime-ses"; | |
| 5 | −import type { LocalExecutorConfig, LocalExecutorRuntime } from "#schema"; | |
| 1 | +import type { | |
| 2 | + CodeExecutor, | |
| 3 | +} from "@executor/codemode-core"; | |
| 4 | +import { | |
| 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 | 18 | const DEFAULT_EXECUTION_RUNTIME: LocalExecutorRuntime = "quickjs"; |
| 8 | 19 | |
| @@ -1,15 +1,32 @@ | ||
| 1 | −import { type ToolPath, makeToolInvokerFromTools } from "@executor/codemode-core"; | |
| 2 | −import type { Source } from "#schema"; | |
| 1 | +import { | |
| 2 | + type ToolPath, | |
| 3 | + makeToolInvokerFromTools, | |
| 4 | +} from "@executor/codemode-core"; | |
| 5 | +import type { | |
| 6 | + Source, | |
| 7 | +} from "#schema"; | |
| 3 | 8 | import * as Either from "effect/Either"; |
| 4 | 9 | import * as Effect from "effect/Effect"; |
| 5 | 10 | import * as Schema from "effect/Schema"; |
| 6 | 11 | |
| 7 | −import type { LoadedSourceCatalogToolIndexEntry } from "../../catalog/source/runtime"; | |
| 8 | −import type { SecretMaterialResolveContext } from "../../workspace/secret-material-providers"; | |
| 9 | −import type { WorkspaceStorageServices } from "../../workspace/storage"; | |
| 10 | −import { invocationDescriptorFromTool } from "../ir-execution"; | |
| 11 | −import { evaluateInvocationPolicy } from "../../policy/invocation-policy-engine"; | |
| 12 | −import { loadRuntimeLocalWorkspacePolicies } from "../../../policies/operations"; | |
| 12 | +import type { | |
| 13 | + LoadedSourceCatalogToolIndexEntry, | |
| 14 | +} from "../../catalog/source/runtime"; | |
| 15 | +import type { | |
| 16 | + SecretMaterialResolveContext, | |
| 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 | 31 | const asToolPath = (value: string): ToolPath => value as ToolPath; |
| 15 | 32 | |
| @@ -64,23 +81,23 @@ export const toSecretResolutionContext = ( · 48 unmodified lines | ||
| 64 | 81 | const failAuthorization = (message: string): Effect.Effect<never, Error, never> => |
| 65 | 82 | Effect.fail(new Error(message)); |
| 66 | 83 | |
| 67 | −type WorkspaceToolElicitation = Parameters< | |
| 84 | +type ScopeToolElicitation = Parameters< | |
| 68 | 85 | typeof makeToolInvokerFromTools |
| 69 | 86 | >[0]["onElicitation"]; |
| 70 | 87 | |
| 71 | 88 | export const authorizePersistedToolInvocation = (input: { |
| 72 | − workspaceId: Source["workspaceId"]; | |
| 89 | + scopeId: Source["scopeId"]; | |
| 73 | 90 | tool: LoadedSourceCatalogToolIndexEntry; |
| 74 | 91 | args: unknown; |
| 75 | 92 | context?: Record<string, unknown>; |
| 76 | − onElicitation?: WorkspaceToolElicitation; | |
| 77 | −}): Effect.Effect<void, Error, WorkspaceStorageServices> => | |
| 93 | + onElicitation?: ScopeToolElicitation; | |
| 94 | +}): Effect.Effect<void, Error, ScopeStorageServices> => | |
| 78 | 95 | Effect.gen(function* () { |
| 79 | 96 | const descriptor = invocationDescriptorFromTool({ |
| 80 | 97 | tool: input.tool, |
| 81 | 98 | }); |
| 82 | − const localWorkspacePolicies = yield* loadRuntimeLocalWorkspacePolicies( | |
| 83 | − input.workspaceId, | |
| 99 | + const localScopePolicies = yield* loadRuntimeLocalScopePolicies( | |
| 100 | + input.scopeId, | |
| 84 | 101 | ).pipe( |
| 85 | 102 | Effect.mapError((cause) => |
| 86 | 103 | cause instanceof Error ? cause : new Error(String(cause)), |
| @@ -90,9 +107,9 @@ export const authorizePersistedToolInvocation = (input: { · 3 unmodified lines | ||
| 90 | 107 | const decision = evaluateInvocationPolicy({ |
| 91 | 108 | descriptor, |
| 92 | 109 | args: input.args, |
| 93 | − policies: localWorkspacePolicies.policies, | |
| 110 | + policies: localScopePolicies.policies, | |
| 94 | 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 | 14 | createCodeExecutorForRuntime, |
| 15 | 15 | resolveConfiguredExecutionRuntime, |
| 16 | 16 | } from "../runtime"; |
| 17 | −import { createWorkspaceToolInvoker } from "./tool-invoker"; | |
| 18 | −import { RuntimeSourceAuthServiceTag } from "../../sources/source-auth-service"; | |
| 19 | −import { RuntimeSourceCatalogStoreService } from "../../catalog/source/runtime"; | |
| 20 | −import { RuntimeSourceAuthMaterialService } from "../../auth/source-auth-material"; | |
| 21 | −import { RuntimeSourceCatalogSyncService } from "../../catalog/source/sync"; | |
| 22 | −import { getRuntimeLocalWorkspaceOption } from "../../workspace/runtime-context"; | |
| 17 | +import { | |
| 18 | + createScopeToolInvoker, | |
| 19 | +} from "./tool-invoker"; | |
| 20 | +import { | |
| 21 | + RuntimeSourceAuthServiceTag, | |
| 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 | 35 | import { |
| 24 | 36 | LocalInstanceConfigService, |
| 25 | 37 | SecretMaterialDeleterService, |
| 26 | 38 | SecretMaterialStorerService, |
| 27 | 39 | SecretMaterialUpdaterService, |
| 28 | −} from "../../workspace/secret-material-providers"; | |
| 40 | +} from "../../scope/secret-material-providers"; | |
| 29 | 41 | import { |
| 30 | 42 | LocalToolRuntimeLoaderService, |
| 31 | 43 | type LocalToolRuntimeLoaderShape, |
| @@ -36,14 +48,20 @@ import { · 4 unmodified lines | ||
| 36 | 48 | type InstallationStoreShape, |
| 37 | 49 | SourceArtifactStore, |
| 38 | 50 | type SourceArtifactStoreShape, |
| 39 | − WorkspaceConfigStore, | |
| 40 | − type WorkspaceConfigStoreShape, | |
| 41 | − WorkspaceStateStore, | |
| 42 | − type WorkspaceStateStoreShape, | |
| 43 | −} from "../../workspace/storage"; | |
| 44 | −import { ExecutorStateStore } from "../../executor-state-store"; | |
| 45 | −import { RuntimeSourceStoreService } from "../../sources/source-store"; | |
| 46 | −import type { CreateWorkspaceInternalToolMap } from "./tool-invoker"; | |
| 51 | + ScopeConfigStore, | |
| 52 | + type ScopeConfigStoreShape, | |
| 53 | + ScopeStateStore, | |
| 54 | + type ScopeStateStoreShape, | |
| 55 | +} from "../../scope/storage"; | |
| 56 | +import { | |
| 57 | + ExecutorStateStore, | |
| 58 | +} from "../../executor-state-store"; | |
| 59 | +import { | |
| 60 | + RuntimeSourceStoreService, | |
| 61 | +} from "../../sources/source-store"; | |
| 62 | +import type { | |
| 63 | + CreateScopeInternalToolMap, | |
| 64 | +} from "./tool-invoker"; | |
| 47 | 65 | export { |
| 48 | 66 | createCodeExecutorForRuntime, |
| 49 | 67 | resolveConfiguredExecutionRuntime, |
| @@ -56,7 +74,7 @@ const createEmptyLocalToolRuntime = (): LocalToolRuntime => ({ · 6 unmodified lines | ||
| 56 | 74 | toolPaths: new Set<string>(), |
| 57 | 75 | }); |
| 58 | 76 | |
| 59 | −export const createWorkspaceExecutionEnvironmentResolver = | |
| 77 | +export const createScopeExecutionEnvironmentResolver = | |
| 60 | 78 | (input: { |
| 61 | 79 | executorStateStore: Effect.Effect.Success<typeof ExecutorStateStore>; |
| 62 | 80 | sourceStore: Effect.Effect.Success<typeof RuntimeSourceStoreService>; |
| @@ -78,25 +96,25 @@ export const createWorkspaceExecutionEnvironmentResolver = · 15 unmodified lines | ||
| 78 | 96 | storeSecretMaterial: Effect.Effect.Success<typeof SecretMaterialStorerService>; |
| 79 | 97 | deleteSecretMaterial: Effect.Effect.Success<typeof SecretMaterialDeleterService>; |
| 80 | 98 | updateSecretMaterial: Effect.Effect.Success<typeof SecretMaterialUpdaterService>; |
| 81 | − workspaceConfigStore: WorkspaceConfigStoreShape; | |
| 82 | − workspaceStateStore: WorkspaceStateStoreShape; | |
| 99 | + scopeConfigStore: ScopeConfigStoreShape; | |
| 100 | + scopeStateStore: ScopeStateStoreShape; | |
| 83 | 101 | sourceArtifactStore: SourceArtifactStoreShape; |
| 84 | − createInternalToolMap?: CreateWorkspaceInternalToolMap; | |
| 102 | + createInternalToolMap?: CreateScopeInternalToolMap; | |
| 85 | 103 | }): ResolveExecutionEnvironment => |
| 86 | − ({ workspaceId, accountId, onElicitation }) => | |
| 104 | + ({ scopeId, actorScopeId, onElicitation }) => | |
| 87 | 105 | Effect.gen(function* () { |
| 88 | − const runtimeLocalWorkspace = yield* getRuntimeLocalWorkspaceOption(); | |
| 106 | + const runtimeLocalScope = yield* getRuntimeLocalScopeOption(); | |
| 89 | 107 | const loadedConfig = |
| 90 | − runtimeLocalWorkspace === null | |
| 108 | + runtimeLocalScope === null | |
| 91 | 109 | ? null |
| 92 | − : yield* input.workspaceConfigStore.load(); | |
| 110 | + : yield* input.scopeConfigStore.load(); | |
| 93 | 111 | const localToolRuntime = |
| 94 | − runtimeLocalWorkspace === null | |
| 112 | + runtimeLocalScope === null | |
| 95 | 113 | ? createEmptyLocalToolRuntime() |
| 96 | 114 | : yield* input.localToolRuntimeLoader.load(); |
| 97 | − const { catalog, toolInvoker } = createWorkspaceToolInvoker({ | |
| 98 | − workspaceId, | |
| 99 | − accountId, | |
| 115 | + const { catalog, toolInvoker } = createScopeToolInvoker({ | |
| 116 | + scopeId, | |
| 117 | + actorScopeId, | |
| 100 | 118 | executorStateStore: input.executorStateStore, |
| 101 | 119 | sourceStore: input.sourceStore, |
| 102 | 120 | sourceCatalogSyncService: input.sourceCatalogSyncService, |
| @@ -106,12 +124,12 @@ export const createWorkspaceExecutionEnvironmentResolver = · 3 unmodified lines | ||
| 106 | 124 | storeSecretMaterial: input.storeSecretMaterial, |
| 107 | 125 | deleteSecretMaterial: input.deleteSecretMaterial, |
| 108 | 126 | updateSecretMaterial: input.updateSecretMaterial, |
| 109 | − workspaceConfigStore: input.workspaceConfigStore, | |
| 110 | − workspaceStateStore: input.workspaceStateStore, | |
| 127 | + scopeConfigStore: input.scopeConfigStore, | |
| 128 | + scopeStateStore: input.scopeStateStore, | |
| 111 | 129 | sourceArtifactStore: input.sourceArtifactStore, |
| 112 | 130 | sourceAuthMaterialService: input.sourceAuthMaterialService, |
| 113 | 131 | sourceAuthService: input.sourceAuthService, |
| 114 | − runtimeLocalWorkspace, | |
| 132 | + runtimeLocalScope, | |
| 115 | 133 | localToolRuntime, |
| 116 | 134 | createInternalToolMap: input.createInternalToolMap, |
| 117 | 135 | onElicitation, |
| @@ -132,13 +150,13 @@ export class RuntimeExecutionResolverService extends Context.Tag( · 14 unmodified lines | ||
| 132 | 150 | "#runtime/RuntimeExecutionResolverService", |
| 133 | 151 | )< |
| 134 | 152 | RuntimeExecutionResolverService, |
| 135 | − ReturnType<typeof createWorkspaceExecutionEnvironmentResolver> | |
| 153 | + ReturnType<typeof createScopeExecutionEnvironmentResolver> | |
| 136 | 154 | >() {} |
| 137 | 155 | |
| 138 | 156 | export const RuntimeExecutionResolverLive = ( |
| 139 | 157 | input: { |
| 140 | 158 | executionResolver?: ResolveExecutionEnvironment; |
| 141 | − createInternalToolMap?: CreateWorkspaceInternalToolMap; | |
| 159 | + createInternalToolMap?: CreateScopeInternalToolMap; | |
| 142 | 160 | } = {}, |
| 143 | 161 | ) => |
| 144 | 162 | input.executionResolver |
| @@ -160,11 +178,11 @@ export const RuntimeExecutionResolverLive = ( · 15 unmodified lines | ||
| 160 | 178 | const storeSecretMaterial = yield* SecretMaterialStorerService; |
| 161 | 179 | const deleteSecretMaterial = yield* SecretMaterialDeleterService; |
| 162 | 180 | const updateSecretMaterial = yield* SecretMaterialUpdaterService; |
| 163 | − const workspaceConfigStore = yield* WorkspaceConfigStore; | |
| 164 | − const workspaceStateStore = yield* WorkspaceStateStore; | |
| 181 | + const scopeConfigStore = yield* ScopeConfigStore; | |
| 182 | + const scopeStateStore = yield* ScopeStateStore; | |
| 165 | 183 | const sourceArtifactStore = yield* SourceArtifactStore; |
| 166 | 184 | |
| 167 | − return createWorkspaceExecutionEnvironmentResolver({ | |
| 185 | + return createScopeExecutionEnvironmentResolver({ | |
| 168 | 186 | executorStateStore, |
| 169 | 187 | sourceStore, |
| 170 | 188 | sourceCatalogSyncService, |
| @@ -177,8 +195,8 @@ export const RuntimeExecutionResolverLive = ( · 6 unmodified lines | ||
| 177 | 195 | storeSecretMaterial, |
| 178 | 196 | deleteSecretMaterial, |
| 179 | 197 | updateSecretMaterial, |
| 180 | − workspaceConfigStore, | |
| 181 | − workspaceStateStore, | |
| 198 | + scopeConfigStore, | |
| 199 | + scopeStateStore, | |
| 182 | 200 | sourceArtifactStore, |
| 183 | 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 | 2 | createToolCatalogFromEntries, |
| 3 | 3 | type ToolCatalog, |
| 4 | 4 | } from "@executor/codemode-core"; |
| 5 | −import type { AccountId, Source } from "#schema"; | |
| 5 | +import type { | |
| 6 | + ScopeId, | |
| 7 | + Source, | |
| 8 | +} from "#schema"; | |
| 6 | 9 | import * as Effect from "effect/Effect"; |
| 7 | 10 | |
| 8 | 11 | import { |
| @@ -10,15 +13,19 @@ import { · 1 unmodified line | ||
| 10 | 13 | type LoadedSourceCatalogToolIndexEntry, |
| 11 | 14 | catalogToolCatalogEntry, |
| 12 | 15 | } from "../../catalog/source/runtime"; |
| 13 | −import type { RuntimeLocalWorkspaceState } from "../../workspace/runtime-context"; | |
| 16 | +import type { | |
| 17 | + RuntimeLocalScopeState, | |
| 18 | +} from "../../scope/runtime-context"; | |
| 14 | 19 | import { |
| 15 | − makeWorkspaceStorageLayer, | |
| 20 | + makeScopeStorageLayer, | |
| 16 | 21 | type SourceArtifactStoreShape, |
| 17 | − type WorkspaceConfigStoreShape, | |
| 18 | − type WorkspaceStateStoreShape, | |
| 19 | − type WorkspaceStorageServices, | |
| 20 | −} from "../../workspace/storage"; | |
| 21 | −import { provideRuntimeLocalWorkspace } from "./local"; | |
| 22 | + type ScopeConfigStoreShape, | |
| 23 | + type ScopeStateStoreShape, | |
| 24 | + type ScopeStorageServices, | |
| 25 | +} from "../../scope/storage"; | |
| 26 | +import { | |
| 27 | + provideRuntimeLocalScope, | |
| 28 | +} from "./local"; | |
| 22 | 29 | |
| 23 | 30 | const tokenize = (value: string): string[] => |
| 24 | 31 | value |
| @@ -74,19 +81,19 @@ const queryTokenWeight = (token: string): number => · 49 unmodified lines | ||
| 74 | 81 | LOW_SIGNAL_QUERY_TOKENS.has(token) ? 0.25 : 1; |
| 75 | 82 | |
| 76 | 83 | export const loadWorkspaceCatalogTools = (input: { |
| 77 | − workspaceId: Source["workspaceId"]; | |
| 78 | − accountId: AccountId; | |
| 84 | + scopeId: Source["scopeId"]; | |
| 85 | + actorScopeId: ScopeId; | |
| 79 | 86 | sourceCatalogStore: Effect.Effect.Success<typeof RuntimeSourceCatalogStoreService>; |
| 80 | 87 | includeSchemas: boolean; |
| 81 | 88 | }): Effect.Effect< |
| 82 | 89 | readonly LoadedSourceCatalogToolIndexEntry[], |
| 83 | 90 | Error, |
| 84 | − WorkspaceStorageServices | |
| 91 | + ScopeStorageServices | |
| 85 | 92 | > => |
| 86 | 93 | Effect.map( |
| 87 | 94 | input.sourceCatalogStore.loadWorkspaceSourceCatalogToolIndex({ |
| 88 | − workspaceId: input.workspaceId, | |
| 89 | − actorAccountId: input.accountId, | |
| 95 | + scopeId: input.scopeId, | |
| 96 | + actorScopeId: input.actorScopeId, | |
| 90 | 97 | includeSchemas: input.includeSchemas, |
| 91 | 98 | }), |
| 92 | 99 | (tools) => |
| @@ -96,20 +103,20 @@ export const loadWorkspaceCatalogTools = (input: { · 3 unmodified lines | ||
| 96 | 103 | ); |
| 97 | 104 | |
| 98 | 105 | export const loadWorkspaceCatalogToolByPath = (input: { |
| 99 | − workspaceId: Source["workspaceId"]; | |
| 100 | − accountId: AccountId; | |
| 106 | + scopeId: Source["scopeId"]; | |
| 107 | + actorScopeId: ScopeId; | |
| 101 | 108 | sourceCatalogStore: Effect.Effect.Success<typeof RuntimeSourceCatalogStoreService>; |
| 102 | 109 | path: string; |
| 103 | 110 | includeSchemas: boolean; |
| 104 | 111 | }): Effect.Effect< |
| 105 | 112 | LoadedSourceCatalogToolIndexEntry | null, |
| 106 | 113 | Error, |
| 107 | − WorkspaceStorageServices | |
| 114 | + ScopeStorageServices | |
| 108 | 115 | > => |
| 109 | 116 | input.sourceCatalogStore.loadWorkspaceSourceCatalogToolByPath({ |
| 110 | − workspaceId: input.workspaceId, | |
| 117 | + scopeId: input.scopeId, | |
| 111 | 118 | path: input.path, |
| 112 | − actorAccountId: input.accountId, | |
| 119 | + actorScopeId: input.actorScopeId, | |
| 113 | 120 | includeSchemas: input.includeSchemas, |
| 114 | 121 | }).pipe( |
| 115 | 122 | Effect.map((tool) => |
| @@ -245,28 +252,28 @@ const scoreCatalogTool = ( · 129 unmodified lines | ||
| 245 | 252 | return score; |
| 246 | 253 | }; |
| 247 | 254 | |
| 248 | −export const createWorkspaceSourceCatalog = (input: { | |
| 249 | − workspaceId: Source["workspaceId"]; | |
| 250 | − accountId: AccountId; | |
| 255 | +export const createScopeSourceCatalog = (input: { | |
| 256 | + scopeId: Source["scopeId"]; | |
| 257 | + actorScopeId: ScopeId; | |
| 251 | 258 | sourceCatalogStore: Effect.Effect.Success<typeof RuntimeSourceCatalogStoreService>; |
| 252 | − workspaceConfigStore: WorkspaceConfigStoreShape; | |
| 253 | − workspaceStateStore: WorkspaceStateStoreShape; | |
| 259 | + scopeConfigStore: ScopeConfigStoreShape; | |
| 260 | + scopeStateStore: ScopeStateStoreShape; | |
| 254 | 261 | sourceArtifactStore: SourceArtifactStoreShape; |
| 255 | − runtimeLocalWorkspace: RuntimeLocalWorkspaceState | null; | |
| 262 | + runtimeLocalScope: RuntimeLocalScopeState | null; | |
| 256 | 263 | }): ToolCatalog => { |
| 257 | − const workspaceStorageLayer = makeWorkspaceStorageLayer({ | |
| 258 | − workspaceConfigStore: input.workspaceConfigStore, | |
| 259 | − workspaceStateStore: input.workspaceStateStore, | |
| 264 | + const scopeStorageLayer = makeScopeStorageLayer({ | |
| 265 | + scopeConfigStore: input.scopeConfigStore, | |
| 266 | + scopeStateStore: input.scopeStateStore, | |
| 260 | 267 | sourceArtifactStore: input.sourceArtifactStore, |
| 261 | 268 | }); |
| 262 | 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 | 272 | const createSharedCatalog = (includeSchemas: boolean): Effect.Effect<ToolCatalog, Error, never> => |
| 266 | 273 | provideWorkspaceStorage(Effect.gen(function* () { |
| 267 | 274 | const catalogTools = yield* loadWorkspaceCatalogTools({ |
| 268 | − workspaceId: input.workspaceId, | |
| 269 | − accountId: input.accountId, | |
| 275 | + scopeId: input.scopeId, | |
| 276 | + actorScopeId: input.actorScopeId, | |
| 270 | 277 | sourceCatalogStore: input.sourceCatalogStore, |
| 271 | 278 | includeSchemas, |
| 272 | 279 | }); |
| @@ -283,15 +290,15 @@ export const createWorkspaceSourceCatalog = (input: { · 10 unmodified lines | ||
| 283 | 290 | |
| 284 | 291 | return { |
| 285 | 292 | listNamespaces: ({ limit }) => |
| 286 | − provideRuntimeLocalWorkspace( | |
| 293 | + provideRuntimeLocalScope( | |
| 287 | 294 | Effect.flatMap(createSharedCatalog(false), (catalog) => |
| 288 | 295 | catalog.listNamespaces({ limit }), |
| 289 | 296 | ), |
| 290 | − input.runtimeLocalWorkspace, | |
| 297 | + input.runtimeLocalScope, | |
| 291 | 298 | ), |
| 292 | 299 | |
| 293 | 300 | listTools: ({ namespace, query, limit, includeSchemas = false }) => |
| 294 | − provideRuntimeLocalWorkspace( | |
| 301 | + provideRuntimeLocalScope( | |
| 295 | 302 | Effect.flatMap(createSharedCatalog(includeSchemas), (catalog) => |
| 296 | 303 | catalog.listTools({ |
| 297 | 304 | ...(namespace !== undefined ? { namespace } : {}), |
| @@ -300,19 +307,19 @@ export const createWorkspaceSourceCatalog = (input: { · 2 unmodified lines | ||
| 300 | 307 | includeSchemas, |
| 301 | 308 | }), |
| 302 | 309 | ), |
| 303 | − input.runtimeLocalWorkspace, | |
| 310 | + input.runtimeLocalScope, | |
| 304 | 311 | ), |
| 305 | 312 | |
| 306 | 313 | getToolByPath: ({ path, includeSchemas }) => |
| 307 | − provideRuntimeLocalWorkspace( | |
| 314 | + provideRuntimeLocalScope( | |
| 308 | 315 | Effect.flatMap(createSharedCatalog(includeSchemas), (catalog) => |
| 309 | 316 | catalog.getToolByPath({ path, includeSchemas }), |
| 310 | 317 | ), |
| 311 | − input.runtimeLocalWorkspace, | |
| 318 | + input.runtimeLocalScope, | |
| 312 | 319 | ), |
| 313 | 320 | |
| 314 | 321 | searchTools: ({ query, namespace, limit }) => |
| 315 | − provideRuntimeLocalWorkspace( | |
| 322 | + provideRuntimeLocalScope( | |
| 316 | 323 | Effect.flatMap(createSharedCatalog(false), (catalog) => |
| 317 | 324 | catalog.searchTools({ |
| 318 | 325 | query, |
| @@ -320,7 +327,7 @@ export const createWorkspaceSourceCatalog = (input: { · 1 unmodified line | ||
| 320 | 327 | limit, |
| 321 | 328 | }), |
| 322 | 329 | ), |
| 323 | − input.runtimeLocalWorkspace, | |
| 330 | + input.runtimeLocalScope, | |
| 324 | 331 | ), |
| 325 | 332 | } satisfies ToolCatalog; |
| 326 | 333 | }; |
| @@ -8,46 +8,73 @@ import { · 7 unmodified lines | ||
| 8 | 8 | type ToolMap, |
| 9 | 9 | type ToolInvoker, |
| 10 | 10 | } from "@executor/codemode-core"; |
| 11 | −import type { AccountId, Source } from "#schema"; | |
| 11 | +import type { | |
| 12 | + ScopeId, | |
| 13 | + Source, | |
| 14 | +} from "#schema"; | |
| 12 | 15 | import * as Effect from "effect/Effect"; |
| 13 | 16 | |
| 14 | −import { RuntimeSourceAuthMaterialService } from "../../auth/source-auth-material"; | |
| 15 | −import { RuntimeSourceCatalogStoreService } from "../../catalog/source/runtime"; | |
| 16 | −import type { RuntimeLocalWorkspaceState } from "../../workspace/runtime-context"; | |
| 17 | −import { type LocalToolRuntime } from "../../local-tool-runtime"; | |
| 17 | +import { | |
| 18 | + RuntimeSourceAuthMaterialService, | |
| 19 | +} from "../../auth/source-auth-material"; | |
| 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 | 29 | import { |
| 19 | 30 | type InstallationStoreShape, |
| 20 | − makeWorkspaceStorageLayer, | |
| 31 | + makeScopeStorageLayer, | |
| 21 | 32 | type SourceArtifactStoreShape, |
| 22 | − type WorkspaceConfigStoreShape, | |
| 23 | − type WorkspaceStateStoreShape, | |
| 24 | −} from "../../workspace/storage"; | |
| 33 | + type ScopeConfigStoreShape, | |
| 34 | + type ScopeStateStoreShape, | |
| 35 | +} from "../../scope/storage"; | |
| 25 | 36 | import type { |
| 26 | 37 | DeleteSecretMaterial, |
| 27 | 38 | ResolveInstanceConfig, |
| 28 | 39 | StoreSecretMaterial, |
| 29 | 40 | UpdateSecretMaterial, |
| 30 | −} from "../../workspace/secret-material-providers"; | |
| 31 | −import type { ExecutorStateStoreShape } from "../../executor-state-store"; | |
| 32 | −import { RuntimeSourceAuthService } from "../../sources/source-auth-service"; | |
| 33 | −import { type RuntimeSourceStore } from "../../sources/source-store"; | |
| 34 | −import { createExecutorToolMap } from "../../sources/executor-tools"; | |
| 35 | −import { RuntimeSourceCatalogSyncService } from "../../catalog/source/sync"; | |
| 36 | −import { invokeIrTool } from "../ir-execution"; | |
| 41 | +} from "../../scope/secret-material-providers"; | |
| 42 | +import type { | |
| 43 | + ExecutorStateStoreShape, | |
| 44 | +} from "../../executor-state-store"; | |
| 45 | +import { | |
| 46 | + RuntimeSourceAuthService, | |
| 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 | 60 | import { |
| 38 | 61 | authorizePersistedToolInvocation, |
| 39 | 62 | toSecretResolutionContext, |
| 40 | 63 | } from "./authorization"; |
| 41 | −import { provideRuntimeLocalWorkspace } from "./local"; | |
| 42 | 64 | import { |
| 43 | − createWorkspaceSourceCatalog, | |
| 65 | + provideRuntimeLocalScope, | |
| 66 | +} from "./local"; | |
| 67 | +import { | |
| 68 | + createScopeSourceCatalog, | |
| 44 | 69 | loadWorkspaceCatalogToolByPath, |
| 45 | 70 | } from "./source-catalog"; |
| 46 | −import { runtimeEffectError } from "../../effect-errors"; | |
| 71 | +import { | |
| 72 | + runtimeEffectError, | |
| 73 | +} from "../../effect-errors"; | |
| 47 | 74 | |
| 48 | −export type WorkspaceInternalToolContext = { | |
| 49 | − workspaceId: Source["workspaceId"]; | |
| 50 | − accountId: AccountId; | |
| 75 | +export type ScopeInternalToolContext = { | |
| 76 | + scopeId: Source["scopeId"]; | |
| 77 | + actorScopeId: ScopeId; | |
| 51 | 78 | executorStateStore: ExecutorStateStoreShape; |
| 52 | 79 | sourceStore: RuntimeSourceStore; |
| 53 | 80 | sourceCatalogSyncService: Effect.Effect.Success< |
| @@ -59,19 +86,19 @@ export type WorkspaceInternalToolContext = { · 5 unmodified lines | ||
| 59 | 86 | storeSecretMaterial: StoreSecretMaterial; |
| 60 | 87 | deleteSecretMaterial: DeleteSecretMaterial; |
| 61 | 88 | updateSecretMaterial: UpdateSecretMaterial; |
| 62 | − workspaceConfigStore: WorkspaceConfigStoreShape; | |
| 63 | − workspaceStateStore: WorkspaceStateStoreShape; | |
| 89 | + scopeConfigStore: ScopeConfigStoreShape; | |
| 90 | + scopeStateStore: ScopeStateStoreShape; | |
| 64 | 91 | sourceArtifactStore: SourceArtifactStoreShape; |
| 65 | − runtimeLocalWorkspace: RuntimeLocalWorkspaceState | null; | |
| 92 | + runtimeLocalScope: RuntimeLocalScopeState | null; | |
| 66 | 93 | }; |
| 67 | 94 | |
| 68 | −export type CreateWorkspaceInternalToolMap = ( | |
| 69 | − input: WorkspaceInternalToolContext, | |
| 95 | +export type CreateScopeInternalToolMap = ( | |
| 96 | + input: ScopeInternalToolContext, | |
| 70 | 97 | ) => ToolMap; |
| 71 | 98 | |
| 72 | −export const createWorkspaceToolInvoker = (input: { | |
| 73 | − workspaceId: Source["workspaceId"]; | |
| 74 | − accountId: AccountId; | |
| 99 | +export const createScopeToolInvoker = (input: { | |
| 100 | + scopeId: Source["scopeId"]; | |
| 101 | + actorScopeId: ScopeId; | |
| 75 | 102 | executorStateStore: ExecutorStateStoreShape; |
| 76 | 103 | sourceStore: RuntimeSourceStore; |
| 77 | 104 | sourceCatalogSyncService: Effect.Effect.Success< |
| @@ -85,16 +112,16 @@ export const createWorkspaceToolInvoker = (input: { · 7 unmodified lines | ||
| 85 | 112 | storeSecretMaterial: StoreSecretMaterial; |
| 86 | 113 | deleteSecretMaterial: DeleteSecretMaterial; |
| 87 | 114 | updateSecretMaterial: UpdateSecretMaterial; |
| 88 | − workspaceConfigStore: WorkspaceConfigStoreShape; | |
| 89 | − workspaceStateStore: WorkspaceStateStoreShape; | |
| 115 | + scopeConfigStore: ScopeConfigStoreShape; | |
| 116 | + scopeStateStore: ScopeStateStoreShape; | |
| 90 | 117 | sourceArtifactStore: SourceArtifactStoreShape; |
| 91 | 118 | sourceAuthMaterialService: Effect.Effect.Success< |
| 92 | 119 | typeof RuntimeSourceAuthMaterialService |
| 93 | 120 | >; |
| 94 | 121 | sourceAuthService: RuntimeSourceAuthService; |
| 95 | − runtimeLocalWorkspace: RuntimeLocalWorkspaceState | null; | |
| 122 | + runtimeLocalScope: RuntimeLocalScopeState | null; | |
| 96 | 123 | localToolRuntime: LocalToolRuntime; |
| 97 | − createInternalToolMap?: CreateWorkspaceInternalToolMap; | |
| 124 | + createInternalToolMap?: CreateScopeInternalToolMap; | |
| 98 | 125 | onElicitation?: Parameters< |
| 99 | 126 | typeof makeToolInvokerFromTools |
| 100 | 127 | >[0]["onElicitation"]; |
| @@ -102,28 +129,28 @@ export const createWorkspaceToolInvoker = (input: { · 1 unmodified line | ||
| 102 | 129 | catalog: ToolCatalog; |
| 103 | 130 | toolInvoker: ToolInvoker; |
| 104 | 131 | } => { |
| 105 | − const workspaceStorageLayer = makeWorkspaceStorageLayer({ | |
| 106 | − workspaceConfigStore: input.workspaceConfigStore, | |
| 107 | − workspaceStateStore: input.workspaceStateStore, | |
| 132 | + const scopeStorageLayer = makeScopeStorageLayer({ | |
| 133 | + scopeConfigStore: input.scopeConfigStore, | |
| 134 | + scopeStateStore: input.scopeStateStore, | |
| 108 | 135 | sourceArtifactStore: input.sourceArtifactStore, |
| 109 | 136 | }); |
| 110 | 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 | 140 | const executorTools = createExecutorToolMap({ |
| 114 | − workspaceId: input.workspaceId, | |
| 115 | − accountId: input.accountId, | |
| 141 | + scopeId: input.scopeId, | |
| 142 | + actorScopeId: input.actorScopeId, | |
| 116 | 143 | sourceAuthService: input.sourceAuthService, |
| 117 | 144 | installationStore: input.installationStore, |
| 118 | − workspaceConfigStore: input.workspaceConfigStore, | |
| 119 | − workspaceStateStore: input.workspaceStateStore, | |
| 145 | + scopeConfigStore: input.scopeConfigStore, | |
| 146 | + scopeStateStore: input.scopeStateStore, | |
| 120 | 147 | sourceArtifactStore: input.sourceArtifactStore, |
| 121 | − runtimeLocalWorkspace: input.runtimeLocalWorkspace, | |
| 148 | + runtimeLocalScope: input.runtimeLocalScope, | |
| 122 | 149 | }); |
| 123 | 150 | const internalTools = |
| 124 | 151 | input.createInternalToolMap?.({ |
| 125 | − workspaceId: input.workspaceId, | |
| 126 | − accountId: input.accountId, | |
| 152 | + scopeId: input.scopeId, | |
| 153 | + actorScopeId: input.actorScopeId, | |
| 127 | 154 | executorStateStore: input.executorStateStore, |
| 128 | 155 | sourceStore: input.sourceStore, |
| 129 | 156 | sourceCatalogSyncService: input.sourceCatalogSyncService, |
| @@ -133,19 +160,19 @@ export const createWorkspaceToolInvoker = (input: { · 3 unmodified lines | ||
| 133 | 160 | storeSecretMaterial: input.storeSecretMaterial, |
| 134 | 161 | deleteSecretMaterial: input.deleteSecretMaterial, |
| 135 | 162 | updateSecretMaterial: input.updateSecretMaterial, |
| 136 | − workspaceConfigStore: input.workspaceConfigStore, | |
| 137 | − workspaceStateStore: input.workspaceStateStore, | |
| 163 | + scopeConfigStore: input.scopeConfigStore, | |
| 164 | + scopeStateStore: input.scopeStateStore, | |
| 138 | 165 | sourceArtifactStore: input.sourceArtifactStore, |
| 139 | − runtimeLocalWorkspace: input.runtimeLocalWorkspace, | |
| 166 | + runtimeLocalScope: input.runtimeLocalScope, | |
| 140 | 167 | }) ?? {}; |
| 141 | − const sourceCatalog = createWorkspaceSourceCatalog({ | |
| 142 | − workspaceId: input.workspaceId, | |
| 143 | − accountId: input.accountId, | |
| 168 | + const sourceCatalog = createScopeSourceCatalog({ | |
| 169 | + scopeId: input.scopeId, | |
| 170 | + actorScopeId: input.actorScopeId, | |
| 144 | 171 | sourceCatalogStore: input.sourceCatalogStore, |
| 145 | − workspaceConfigStore: input.workspaceConfigStore, | |
| 146 | − workspaceStateStore: input.workspaceStateStore, | |
| 172 | + scopeConfigStore: input.scopeConfigStore, | |
| 173 | + scopeStateStore: input.scopeStateStore, | |
| 147 | 174 | sourceArtifactStore: input.sourceArtifactStore, |
| 148 | − runtimeLocalWorkspace: input.runtimeLocalWorkspace, | |
| 175 | + runtimeLocalScope: input.runtimeLocalScope, | |
| 149 | 176 | }); |
| 150 | 177 | let catalog: ToolCatalog | null = null; |
| 151 | 178 | const systemTools = createSystemToolMap({ |
| @@ -180,25 +207,25 @@ export const createWorkspaceToolInvoker = (input: { · 28 unmodified lines | ||
| 180 | 207 | args: unknown; |
| 181 | 208 | context?: Record<string, unknown>; |
| 182 | 209 | }) => |
| 183 | − provideRuntimeLocalWorkspace( | |
| 210 | + provideRuntimeLocalScope( | |
| 184 | 211 | provideWorkspaceStorage( |
| 185 | 212 | Effect.gen(function* () { |
| 186 | 213 | const catalogTool = yield* loadWorkspaceCatalogToolByPath({ |
| 187 | − workspaceId: input.workspaceId, | |
| 188 | − accountId: input.accountId, | |
| 214 | + scopeId: input.scopeId, | |
| 215 | + actorScopeId: input.actorScopeId, | |
| 189 | 216 | sourceCatalogStore: input.sourceCatalogStore, |
| 190 | 217 | path: invocation.path, |
| 191 | 218 | includeSchemas: false, |
| 192 | 219 | }); |
| 193 | 220 | if (!catalogTool) { |
| 194 | 221 | return yield* runtimeEffectError( |
| 195 | − "execution/workspace/tool-invoker", | |
| 222 | + "execution/scope/tool-invoker", | |
| 196 | 223 | `Unknown tool path: ${invocation.path}`, |
| 197 | 224 | ); |
| 198 | 225 | } |
| 199 | 226 | |
| 200 | 227 | yield* authorizePersistedToolInvocation({ |
| 201 | − workspaceId: input.workspaceId, | |
| 228 | + scopeId: input.scopeId, | |
| 202 | 229 | tool: catalogTool, |
| 203 | 230 | args: invocation.args, |
| 204 | 231 | context: invocation.context, |
| @@ -207,12 +234,12 @@ export const createWorkspaceToolInvoker = (input: { · 2 unmodified lines | ||
| 207 | 234 | |
| 208 | 235 | const auth = yield* input.sourceAuthMaterialService.resolve({ |
| 209 | 236 | source: catalogTool.source, |
| 210 | − actorAccountId: input.accountId, | |
| 237 | + actorScopeId: input.actorScopeId, | |
| 211 | 238 | context: toSecretResolutionContext(invocation.context), |
| 212 | 239 | }); |
| 213 | 240 | return yield* invokeIrTool({ |
| 214 | − workspaceId: input.workspaceId, | |
| 215 | − accountId: input.accountId, | |
| 241 | + scopeId: input.scopeId, | |
| 242 | + actorScopeId: input.actorScopeId, | |
| 216 | 243 | tool: catalogTool, |
| 217 | 244 | auth, |
| 218 | 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 | 254 | return { |
| 228 | 255 | catalog, |
| 229 | 256 | toolInvoker: { |
| 230 | 257 | invoke: ({ path, args, context }) => |
| 231 | − provideRuntimeLocalWorkspace( | |
| 258 | + provideRuntimeLocalScope( | |
| 232 | 259 | authoredToolPaths.has(path) |
| 233 | 260 | ? authoredInvoker.invoke({ path, args, context }) |
| 234 | 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 | 16 | ExecutionIdSchema, |
| 17 | 17 | ExecutionInteractionIdSchema, |
| 18 | 18 | ExecutionStepIdSchema, |
| 19 | − type AccountId, | |
| 19 | + type ScopeId, | |
| 20 | 20 | type Execution, |
| 21 | 21 | type ExecutionEnvelope, |
| 22 | 22 | type ExecutionId, |
| 23 | 23 | type ExecutionInteraction, |
| 24 | − type WorkspaceId, | |
| 25 | 24 | } from "#schema"; |
| 26 | 25 | import * as Data from "effect/Data"; |
| 27 | 26 | import * as Deferred from "effect/Deferred"; |
| @@ -29,16 +28,18 @@ import * as Effect from "effect/Effect"; · 1 unmodified line | ||
| 29 | 28 | import * as Option from "effect/Option"; |
| 30 | 29 | import * as Schema from "effect/Schema"; |
| 31 | 30 | |
| 32 | −import { type ResolveExecutionEnvironment } from "./state"; | |
| 31 | +import { | |
| 32 | + type ResolveExecutionEnvironment, | |
| 33 | +} from "./state"; | |
| 33 | 34 | import { |
| 34 | 35 | LiveExecutionManagerService, |
| 35 | 36 | sanitizePersistedElicitationResponse, |
| 36 | 37 | type LiveExecutionManager, |
| 37 | 38 | } from "./live"; |
| 38 | 39 | import { |
| 39 | − getRuntimeLocalWorkspaceOption, | |
| 40 | − provideOptionalRuntimeLocalWorkspace, | |
| 41 | −} from "../workspace/runtime-context"; | |
| 40 | + getRuntimeLocalScopeOption, | |
| 41 | + provideOptionalRuntimeLocalScope, | |
| 42 | +} from "../scope/runtime-context"; | |
| 42 | 43 | import { |
| 43 | 44 | asOperationErrors, |
| 44 | 45 | operationErrors, |
| @@ -48,8 +49,12 @@ import { · 3 unmodified lines | ||
| 48 | 49 | ExecutorStateStore, |
| 49 | 50 | type ExecutorStateStoreShape, |
| 50 | 51 | } from "../executor-state-store"; |
| 51 | −import { RuntimeExecutionResolverService } from "./workspace/environment"; | |
| 52 | −import { runtimeEffectError } from "../effect-errors"; | |
| 52 | +import { | |
| 53 | + RuntimeExecutionResolverService, | |
| 54 | +} from "./scope/environment"; | |
| 55 | +import { | |
| 56 | + runtimeEffectError, | |
| 57 | +} from "../effect-errors"; | |
| 53 | 58 | |
| 54 | 59 | const executionOps = { |
| 55 | 60 | create: operationErrors("executions.create"), |
| @@ -246,7 +251,7 @@ const verifyStoredStepMatches = (input: { · 190 unmodified lines | ||
| 246 | 251 | const fetchExecution = ( |
| 247 | 252 | store: ExecutorStateStoreShape, |
| 248 | 253 | input: { |
| 249 | − workspaceId: Execution["workspaceId"]; | |
| 254 | + scopeId: Execution["scopeId"]; | |
| 250 | 255 | executionId: Execution["id"]; |
| 251 | 256 | operation: OperationErrorsLike; |
| 252 | 257 | }, |
| @@ -254,13 +259,13 @@ const fetchExecution = ( · 1 unmodified line | ||
| 254 | 259 | Effect.gen(function* () { |
| 255 | 260 | const errors = asOperationErrors(input.operation); |
| 256 | 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 | 265 | if (Option.isNone(existing)) { |
| 261 | 266 | return yield* errors.notFound( |
| 262 | 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 | 275 | const fetchExecutionEnvelope = ( |
| 271 | 276 | store: ExecutorStateStoreShape, |
| 272 | 277 | input: { |
| 273 | − workspaceId: Execution["workspaceId"]; | |
| 278 | + scopeId: Execution["scopeId"]; | |
| 274 | 279 | executionId: Execution["id"]; |
| 275 | 280 | operation: OperationErrorsLike; |
| 276 | 281 | }, |
| @@ -291,7 +296,7 @@ const fetchExecutionEnvelope = ( · 14 unmodified lines | ||
| 291 | 296 | const waitForExecutionEnvelopeToSettle = ( |
| 292 | 297 | store: ExecutorStateStoreShape, |
| 293 | 298 | input: { |
| 294 | − workspaceId: Execution["workspaceId"]; | |
| 299 | + scopeId: Execution["scopeId"]; | |
| 295 | 300 | executionId: Execution["id"]; |
| 296 | 301 | operation: OperationErrorsLike; |
| 297 | 302 | previousPendingInteractionId: ExecutionInteraction["id"] | null; |
| @@ -658,8 +663,8 @@ const runExecutionAttemptWithDependencies = ( · 360 unmodified lines | ||
| 658 | 663 | interactionMode: InteractionMode, |
| 659 | 664 | ) => |
| 660 | 665 | executionResolver({ |
| 661 | − workspaceId: execution.workspaceId, | |
| 662 | − accountId: execution.createdByAccountId, | |
| 666 | + scopeId: execution.scopeId, | |
| 667 | + actorScopeId: execution.createdByScopeId, | |
| 663 | 668 | executionId: execution.id, |
| 664 | 669 | onElicitation: createHybridOnElicitation({ |
| 665 | 670 | executorState: store, |
| @@ -710,7 +715,7 @@ const forkExecutionAttemptWithDependencies = ( · 44 unmodified lines | ||
| 710 | 715 | interactionMode: InteractionMode, |
| 711 | 716 | ) => |
| 712 | 717 | Effect.gen(function* () { |
| 713 | − const runtimeLocalWorkspace = yield* getRuntimeLocalWorkspaceOption(); | |
| 718 | + const runtimeLocalScope = yield* getRuntimeLocalScopeOption(); | |
| 714 | 719 | |
| 715 | 720 | yield* Effect.sync(() => { |
| 716 | 721 | const effect = runExecutionAttemptWithDependencies( |
| @@ -722,7 +727,7 @@ const forkExecutionAttemptWithDependencies = ( · 5 unmodified lines | ||
| 722 | 727 | ); |
| 723 | 728 | |
| 724 | 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 | 813 | executionResolver: ResolveExecutionEnvironment, |
| 809 | 814 | liveExecutionManager: LiveExecutionManager, |
| 810 | 815 | input: { |
| 811 | − workspaceId: WorkspaceId; | |
| 816 | + scopeId: ScopeId; | |
| 812 | 817 | payload: CreateExecutionPayload; |
| 813 | − createdByAccountId: AccountId; | |
| 818 | + createdByScopeId: ScopeId; | |
| 814 | 819 | }, |
| 815 | 820 | ) => |
| 816 | 821 | Effect.gen(function* () { |
| @@ -818,8 +823,8 @@ const createExecutionWithDependencies = ( · 1 unmodified line | ||
| 818 | 823 | const now = Date.now(); |
| 819 | 824 | const execution: Execution = { |
| 820 | 825 | id: ExecutionIdSchema.make(`exec_${crypto.randomUUID()}`), |
| 821 | − workspaceId: input.workspaceId, | |
| 822 | − createdByAccountId: input.createdByAccountId, | |
| 826 | + scopeId: input.scopeId, | |
| 827 | + createdByScopeId: input.createdByScopeId, | |
| 823 | 828 | status: "pending", |
| 824 | 829 | code, |
| 825 | 830 | resultJson: null, |
| @@ -863,16 +868,16 @@ const createExecutionWithDependencies = ( · 37 unmodified lines | ||
| 863 | 868 | yield* Deferred.await(nextState); |
| 864 | 869 | |
| 865 | 870 | return yield* fetchExecutionEnvelope(store, { |
| 866 | − workspaceId: input.workspaceId, | |
| 871 | + scopeId: input.scopeId, | |
| 867 | 872 | executionId: execution.id, |
| 868 | 873 | operation: executionOps.create, |
| 869 | 874 | }); |
| 870 | 875 | }); |
| 871 | 876 | |
| 872 | 877 | export const createExecution = (input: { |
| 873 | − workspaceId: WorkspaceId; | |
| 878 | + scopeId: ScopeId; | |
| 874 | 879 | payload: CreateExecutionPayload; |
| 875 | − createdByAccountId: AccountId; | |
| 880 | + createdByScopeId: ScopeId; | |
| 876 | 881 | }) => |
| 877 | 882 | Effect.gen(function* () { |
| 878 | 883 | const store = yield* ExecutorStateStore; |
| @@ -888,12 +893,12 @@ export const createExecution = (input: { · 9 unmodified lines | ||
| 888 | 893 | }); |
| 889 | 894 | |
| 890 | 895 | export const getExecution = (input: { |
| 891 | − workspaceId: WorkspaceId; | |
| 896 | + scopeId: ScopeId; | |
| 892 | 897 | executionId: ExecutionId; |
| 893 | 898 | }) => |
| 894 | 899 | Effect.flatMap(ExecutorStateStore, (store) => |
| 895 | 900 | fetchExecutionEnvelope(store, { |
| 896 | − workspaceId: input.workspaceId, | |
| 901 | + scopeId: input.scopeId, | |
| 897 | 902 | executionId: input.executionId, |
| 898 | 903 | operation: executionOps.get, |
| 899 | 904 | }) |
| @@ -921,10 +926,10 @@ export const submitExecutionInteractionResponse = (input: { · 21 unmodified lines | ||
| 921 | 926 | }); |
| 922 | 927 | |
| 923 | 928 | export const resumeExecution = (input: { |
| 924 | − workspaceId: WorkspaceId; | |
| 929 | + scopeId: ScopeId; | |
| 925 | 930 | executionId: ExecutionId; |
| 926 | 931 | payload: ResumeExecutionPayload; |
| 927 | − resumedByAccountId: AccountId; | |
| 932 | + resumedByScopeId: ScopeId; | |
| 928 | 933 | }) => |
| 929 | 934 | Effect.gen(function* () { |
| 930 | 935 | const store = yield* ExecutorStateStore; |
| @@ -932,7 +937,7 @@ export const resumeExecution = (input: { · 1 unmodified line | ||
| 932 | 937 | const liveExecutionManager = yield* LiveExecutionManagerService; |
| 933 | 938 | |
| 934 | 939 | const existing = yield* fetchExecutionEnvelope(store, { |
| 935 | − workspaceId: input.workspaceId, | |
| 940 | + scopeId: input.scopeId, | |
| 936 | 941 | executionId: input.executionId, |
| 937 | 942 | operation: "executions.resume", |
| 938 | 943 | }); |
| @@ -1002,7 +1007,7 @@ export const resumeExecution = (input: { · 63 unmodified lines | ||
| 1002 | 1007 | } |
| 1003 | 1008 | |
| 1004 | 1009 | return yield* waitForExecutionEnvelopeToSettle(store, { |
| 1005 | − workspaceId: input.workspaceId, | |
| 1010 | + scopeId: input.scopeId, | |
| 1006 | 1011 | executionId: input.executionId, |
| 1007 | 1012 | operation: executionOps.resume, |
| 1008 | 1013 | previousPendingInteractionId: existing.pendingInteraction?.id ?? null, |
| @@ -4,7 +4,10 @@ import type { · 3 unmodified lines | ||
| 4 | 4 | ToolCatalog, |
| 5 | 5 | ToolInvoker, |
| 6 | 6 | } from "@executor/codemode-core"; |
| 7 | −import type { AccountId, ExecutionId, WorkspaceId } from "#schema"; | |
| 7 | +import type { | |
| 8 | + ScopeId, | |
| 9 | + ExecutionId, | |
| 10 | +} from "#schema"; | |
| 8 | 11 | import * as Data from "effect/Data"; |
| 9 | 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 | 20 | export type ResolveExecutionEnvironment = (input: { |
| 18 | − workspaceId: WorkspaceId; | |
| 19 | − accountId: AccountId; | |
| 21 | + scopeId: ScopeId; | |
| 22 | + actorScopeId: ScopeId; | |
| 20 | 23 | executionId: ExecutionId; |
| 21 | 24 | onElicitation?: OnElicitation; |
| 22 | 25 | }) => Effect.Effect<ExecutionEnvironment, unknown>; |
| @@ -3,7 +3,9 @@ import { · 2 unmodified lines | ||
| 3 | 3 | HttpApiClient, |
| 4 | 4 | HttpServer, |
| 5 | 5 | } from "@effect/platform"; |
| 6 | −import { NodeHttpServer } from "@effect/platform-node"; | |
| 6 | +import { | |
| 7 | + NodeHttpServer, | |
| 8 | +} from "@effect/platform-node"; | |
| 7 | 9 | import { |
| 8 | 10 | ExecutorApi, |
| 9 | 11 | createExecutorApiLayer, |
| @@ -93,7 +95,7 @@ type ExecutorApiClient = Effect.Effect.Success< · 83 unmodified lines | ||
| 93 | 95 | export const withExecutorApiClient = <A, E>( |
| 94 | 96 | input: { |
| 95 | 97 | runtime: ExecutorRuntime; |
| 96 | − accountId?: string; | |
| 98 | + actorScopeId?: string; | |
| 97 | 99 | }, |
| 98 | 100 | f: (client: ExecutorApiClient) => Effect.Effect<A, E, never>, |
| 99 | 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"; | |
| 2 | −import { join } from "node:path"; | |
| 1 | +import { | |
| 2 | + createServer, | |
| 3 | +} from "node:http"; | |
| 4 | +import { | |
| 5 | + join, | |
| 6 | +} from "node:path"; | |
| 3 | 7 | |
| 4 | −import { FileSystem } from "@effect/platform"; | |
| 5 | −import { NodeFileSystem } from "@effect/platform-node"; | |
| 6 | −import { describe, expect, it } from "@effect/vitest"; | |
| 7 | −import { assertTrue } from "@effect/vitest/utils"; | |
| 8 | +import { | |
| 9 | + FileSystem, | |
| 10 | + HttpApi, | |
| 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 | 27 | import * as Either from "effect/Either"; |
| 9 | 28 | import * as Effect from "effect/Effect"; |
| 10 | 29 | import * as Fiber from "effect/Fiber"; |
| 30 | +import * as Layer from "effect/Layer"; | |
| 11 | 31 | import * as Option from "effect/Option"; |
| 32 | +import * as Schema from "effect/Schema"; | |
| 12 | 33 | |
| 13 | 34 | import { |
| 14 | 35 | ExecutionIdSchema, |
| @@ -18,12 +39,23 @@ import { · 3 unmodified lines | ||
| 18 | 39 | SecretMaterialIdSchema, |
| 19 | 40 | SourceAuthSessionIdSchema, |
| 20 | 41 | SourceIdSchema, |
| 21 | − WorkspaceOauthClientIdSchema, | |
| 42 | + ScopeOauthClientIdSchema, | |
| 22 | 43 | } from "#schema"; |
| 23 | −import type { ToolPath } from "@executor/codemode-core"; | |
| 24 | −import { createCatalogImportMetadata } from "@executor/source-core"; | |
| 25 | −import { createGraphqlCatalogFragment } from "@executor/source-graphql"; | |
| 26 | −import { createWorkspaceExecutorAdminToolMap } from "../../../internal/src/index"; | |
| 44 | +import type { | |
| 45 | + ToolPath, | |
| 46 | +} from "@executor/codemode-core"; | |
| 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 | 60 | import { |
| 29 | 61 | type ExecutorRuntime, |
| @@ -31,14 +63,22 @@ import { · 1 unmodified line | ||
| 31 | 63 | provideExecutorRuntime, |
| 32 | 64 | RuntimeExecutionResolverService, |
| 33 | 65 | } from "./index"; |
| 34 | −import { createSourceFromPayload } from "./sources/source-definitions"; | |
| 35 | −import { decodeSourceCredentialSelectionContent } from "./sources/source-credential-interactions"; | |
| 36 | −import { persistSource } from "./sources/source-store"; | |
| 66 | +import { | |
| 67 | + createSourceFromPayload, | |
| 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 | 75 | import { |
| 38 | 76 | withExecutorApiClient, |
| 39 | 77 | withExecutorApiRequestHandler, |
| 40 | 78 | } from "./execution/test-http-client"; |
| 41 | −import { runtimeEffectError } from "./effect-errors"; | |
| 79 | +import { | |
| 80 | + runtimeEffectError, | |
| 81 | +} from "./effect-errors"; | |
| 42 | 82 | import { |
| 43 | 83 | buildLocalSourceArtifact, |
| 44 | 84 | createLocalExecutorRuntime as createExecutorRuntime, |
| @@ -57,15 +97,15 @@ import { · 12 unmodified lines | ||
| 57 | 97 | |
| 58 | 98 | const makeRuntime = Effect.gen(function* () { |
| 59 | 99 | const fs = yield* FileSystem.FileSystem; |
| 60 | − const workspaceRoot = yield* fs.makeTempDirectoryScoped({ | |
| 100 | + const scopeRoot = yield* fs.makeTempDirectoryScoped({ | |
| 61 | 101 | prefix: "executor-runtime-", |
| 62 | 102 | }); |
| 63 | − const homeConfigPath = join(workspaceRoot, ".executor-home.jsonc"); | |
| 64 | − const homeStateDirectory = join(workspaceRoot, ".executor-home-state"); | |
| 103 | + const homeConfigPath = join(scopeRoot, ".executor-home.jsonc"); | |
| 104 | + const homeStateDirectory = join(scopeRoot, ".executor-home-state"); | |
| 65 | 105 | |
| 66 | 106 | return yield* Effect.acquireRelease( |
| 67 | 107 | createExecutorRuntime({ |
| 68 | − workspaceRoot, | |
| 108 | + workspaceRoot: scopeRoot, | |
| 69 | 109 | homeConfigPath, |
| 70 | 110 | homeStateDirectory, |
| 71 | 111 | createInternalToolMap: createWorkspaceExecutorAdminToolMap, |
| @@ -74,11 +114,19 @@ const makeRuntime = Effect.gen(function* () { · 2 unmodified lines | ||
| 74 | 114 | ); |
| 75 | 115 | }).pipe(Effect.provide(NodeFileSystem.layer)); |
| 76 | 116 | |
| 77 | −type OpenApiSpecServer = { | |
| 78 | − baseUrl: string; | |
| 79 | − specUrl: string; | |
| 80 | − close: () => Promise<void>; | |
| 81 | −}; | |
| 117 | +const ownerParam = HttpApiSchema.param("owner", Schema.String); | |
| 118 | +const repoParam = HttpApiSchema.param("repo", Schema.String); | |
| 119 | + | |
| 120 | +class RuntimeTestReposApi extends HttpApiGroup.make("repos") | |
| 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 | 131 | type GoogleWorkspaceTestServer = { |
| 84 | 132 | baseUrl: string; |
| @@ -99,74 +147,26 @@ type GoogleWorkspaceTestServer = { · 14 unmodified lines | ||
| 99 | 147 | close: () => Promise<void>; |
| 100 | 148 | }; |
| 101 | 149 | |
| 102 | −const makeOpenApiSpecServer = Effect.acquireRelease( | |
| 103 | − Effect.promise<OpenApiSpecServer>( | |
| 104 | − () => | |
| 105 | − new Promise<OpenApiSpecServer>((resolve, reject) => { | |
| 106 | − const openApiDocument = JSON.stringify({ | |
| 107 | − openapi: "3.0.3", | |
| 108 | − info: { | |
| 109 | − title: "GitHub Test API", | |
| 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 | − }); | |
| 150 | +const runtimeTestOpenApiLive = HttpApiBuilder.group( | |
| 151 | + RuntimeTestOpenApi, | |
| 152 | + "repos", | |
| 153 | + (handlers) => | |
| 154 | + handlers.handle("getRepo", ({ path }) => | |
| 155 | + Effect.succeed({ | |
| 156 | + full_name: `${path.owner}/${path.repo}`, | |
| 157 | + private: false, | |
| 165 | 158 | }), |
| 166 | − ), | |
| 167 | − (server) => Effect.promise(() => server.close()).pipe(Effect.orDie), | |
| 159 | + ), | |
| 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 | 170 | const makeGoogleWorkspaceTestServer = Effect.acquireRelease( |
| 171 | 171 | Effect.promise<GoogleWorkspaceTestServer>( |
| 172 | 172 | () => |
| @@ -379,7 +379,7 @@ const createPersistedGoogleSource = (input: { · 206 unmodified lines | ||
| 379 | 379 | Effect.gen(function* () { |
| 380 | 380 | const installation = input.runtime.localInstallation; |
| 381 | 381 | const source = yield* createSourceFromPayload({ |
| 382 | − workspaceId: installation.workspaceId, | |
| 382 | + scopeId: installation.scopeId, | |
| 383 | 383 | sourceId: SourceIdSchema.make(`src_${crypto.randomUUID()}`), |
| 384 | 384 | payload: { |
| 385 | 385 | name: input.name, |
| @@ -402,7 +402,7 @@ const createPersistedGoogleSource = (input: { · 16 unmodified lines | ||
| 402 | 402 | }); |
| 403 | 403 | |
| 404 | 404 | return yield* persistSource(input.runtime.storage.executorState, source, { |
| 405 | − actorAccountId: installation.accountId, | |
| 405 | + actorScopeId: installation.actorScopeId, | |
| 406 | 406 | }).pipe((effect) => provideExecutorRuntime(effect, input.runtime)); |
| 407 | 407 | }); |
| 408 | 408 | |
| @@ -430,8 +430,8 @@ const invokeWorkspaceTool = <A>(input: { · 21 unmodified lines | ||
| 430 | 430 | const installation = input.runtime.localInstallation; |
| 431 | 431 | const resolveEnvironment = yield* RuntimeExecutionResolverService; |
| 432 | 432 | const environment = yield* resolveEnvironment({ |
| 433 | − workspaceId: installation.workspaceId, | |
| 434 | − accountId: installation.accountId, | |
| 433 | + scopeId: installation.scopeId, | |
| 434 | + actorScopeId: installation.actorScopeId, | |
| 435 | 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 | 450 | Effect.gen(function* () { |
| 451 | 451 | const fs = yield* FileSystem.FileSystem; |
| 452 | − const workspaceRoot = yield* fs.makeTempDirectoryScoped({ | |
| 452 | + const scopeRoot = yield* fs.makeTempDirectoryScoped({ | |
| 453 | 453 | prefix: "executor-local-config-runtime-", |
| 454 | 454 | }); |
| 455 | − const homeConfigPath = join(workspaceRoot, ".executor-home.jsonc"); | |
| 456 | − const homeStateDirectory = join(workspaceRoot, ".executor-home-state"); | |
| 455 | + const homeConfigPath = join(scopeRoot, ".executor-home.jsonc"); | |
| 456 | + const homeStateDirectory = join(scopeRoot, ".executor-home-state"); | |
| 457 | 457 | const runtime = yield* Effect.acquireRelease( |
| 458 | 458 | createExecutorRuntime({ |
| 459 | − workspaceRoot, | |
| 459 | + workspaceRoot: scopeRoot, | |
| 460 | 460 | homeConfigPath, |
| 461 | 461 | homeStateDirectory, |
| 462 | 462 | }), |
| @@ -467,10 +467,10 @@ describe("executor-runtime", () => { · 4 unmodified lines | ||
| 467 | 467 | const installation = runtime.localInstallation; |
| 468 | 468 | |
| 469 | 469 | const createdSource = yield* withExecutorApiClient( |
| 470 | − { runtime, accountId: installation.accountId }, | |
| 470 | + { runtime, actorScopeId: installation.actorScopeId }, | |
| 471 | 471 | (client) => |
| 472 | 472 | client.sources.create({ |
| 473 | − path: { workspaceId: installation.workspaceId }, | |
| 473 | + path: { workspaceId: installation.scopeId }, | |
| 474 | 474 | payload: { |
| 475 | 475 | name: "GitHub", |
| 476 | 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 | 489 | const createdConfig = JSON.parse( |
| 490 | 490 | yield* fs.readFileString(configPath, "utf8"), |
| 491 | 491 | ) as { |
| @@ -500,11 +500,11 @@ describe("executor-runtime", () => { · 8 unmodified lines | ||
| 500 | 500 | ); |
| 501 | 501 | |
| 502 | 502 | const removed = yield* withExecutorApiClient( |
| 503 | − { runtime, accountId: installation.accountId }, | |
| 503 | + { runtime, actorScopeId: installation.actorScopeId }, | |
| 504 | 504 | (client) => |
| 505 | 505 | client.sources.remove({ |
| 506 | 506 | path: { |
| 507 | − workspaceId: installation.workspaceId, | |
| 507 | + workspaceId: installation.scopeId, | |
| 508 | 508 | sourceId: createdSource.id, |
| 509 | 509 | }, |
| 510 | 510 | }), |
| @@ -615,11 +615,11 @@ describe("executor-runtime", () => { · 104 unmodified lines | ||
| 615 | 615 | const openApiServer = yield* makeOpenApiSpecServer; |
| 616 | 616 | const installation = runtime.localInstallation; |
| 617 | 617 | const createdSource = yield* withExecutorApiClient( |
| 618 | − { runtime, accountId: installation.accountId }, | |
| 618 | + { runtime, actorScopeId: installation.actorScopeId }, | |
| 619 | 619 | (client) => |
| 620 | 620 | client.sources.create({ |
| 621 | 621 | path: { |
| 622 | − workspaceId: installation.workspaceId, | |
| 622 | + workspaceId: installation.scopeId, | |
| 623 | 623 | }, |
| 624 | 624 | payload: { |
| 625 | 625 | name: "GitHub", |
| @@ -640,15 +640,15 @@ describe("executor-runtime", () => { · 14 unmodified lines | ||
| 640 | 640 | ); |
| 641 | 641 | |
| 642 | 642 | const localInstallation = yield* invokeWorkspaceTool<{ |
| 643 | − workspaceId: string; | |
| 644 | − accountId: string; | |
| 643 | + scopeId: string; | |
| 644 | + actorScopeId: string; | |
| 645 | 645 | }>({ |
| 646 | 646 | runtime, |
| 647 | 647 | path: "executor.local.installation.get" as ToolPath, |
| 648 | 648 | args: {}, |
| 649 | 649 | }); |
| 650 | − expect(localInstallation.workspaceId).toBe(installation.workspaceId); | |
| 651 | − expect(localInstallation.accountId).toBe(installation.accountId); | |
| 650 | + expect(localInstallation.scopeId).toBe(installation.scopeId); | |
| 651 | + expect(localInstallation.actorScopeId).toBe(installation.actorScopeId); | |
| 652 | 652 | |
| 653 | 653 | const localConfig = yield* invokeWorkspaceTool<{ |
| 654 | 654 | defaultSecretStoreProvider: string; |
| @@ -723,11 +723,11 @@ describe("executor-runtime", () => { · 68 unmodified lines | ||
| 723 | 723 | expect(loadedPolicy.id).toBe(createdPolicy.id); |
| 724 | 724 | |
| 725 | 725 | const listedPolicies = yield* withExecutorApiClient( |
| 726 | − { runtime, accountId: installation.accountId }, | |
| 726 | + { runtime, actorScopeId: installation.actorScopeId }, | |
| 727 | 727 | (client) => |
| 728 | 728 | client.policies.list({ |
| 729 | 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 | 768 | expect(removedSource.removed).toBe(true); |
| 769 | 769 | |
| 770 | 770 | const apiSources = yield* withExecutorApiClient( |
| 771 | − { runtime, accountId: installation.accountId }, | |
| 771 | + { runtime, actorScopeId: installation.actorScopeId }, | |
| 772 | 772 | (client) => |
| 773 | 773 | client.sources.list({ |
| 774 | 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 | 799 | yield* runtime.storage.executorState.executions.insert({ |
| 800 | 800 | id: executionId, |
| 801 | − workspaceId: installation.workspaceId, | |
| 802 | − createdByAccountId: installation.accountId, | |
| 801 | + scopeId: installation.scopeId, | |
| 802 | + createdByScopeId: installation.actorScopeId, | |
| 803 | 803 | status: "running", |
| 804 | 804 | code: "return await tools.executor.sources.add(...)", |
| 805 | 805 | resultJson: null, |
| @@ -812,7 +812,7 @@ describe("executor-runtime", () => { · 6 unmodified lines | ||
| 812 | 812 | }); |
| 813 | 813 | |
| 814 | 814 | const localSource = yield* createSourceFromPayload({ |
| 815 | − workspaceId: installation.workspaceId, | |
| 815 | + scopeId: installation.scopeId, | |
| 816 | 816 | sourceId, |
| 817 | 817 | payload: { |
| 818 | 818 | name: "GitHub", |
| @@ -832,7 +832,7 @@ describe("executor-runtime", () => { · 13 unmodified lines | ||
| 832 | 832 | now, |
| 833 | 833 | }).pipe(Effect.orDie); |
| 834 | 834 | yield* persistSource(runtime.storage.executorState, localSource, { |
| 835 | − actorAccountId: installation.accountId, | |
| 835 | + actorScopeId: installation.actorScopeId, | |
| 836 | 836 | }).pipe( |
| 837 | 837 | (effect) => provideExecutorRuntime(effect, runtime), |
| 838 | 838 | Effect.orDie, |
| @@ -854,13 +854,13 @@ describe("executor-runtime", () => { · 15 unmodified lines | ||
| 854 | 854 | endpoint: "https://api.github.com", |
| 855 | 855 | specUrl: "https://example.com/github-openapi.yaml", |
| 856 | 856 | name: "GitHub", |
| 857 | − workspaceId: installation.workspaceId, | |
| 857 | + scopeId: installation.scopeId, | |
| 858 | 858 | sourceId, |
| 859 | 859 | }, |
| 860 | 860 | elicitation: { |
| 861 | 861 | mode: "url", |
| 862 | 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 | 864 | elicitationId: interactionSuffix, |
| 865 | 865 | }, |
| 866 | 866 | }); |
| @@ -893,7 +893,7 @@ describe("executor-runtime", () => { · 26 unmodified lines | ||
| 893 | 893 | (handleRequest) => |
| 894 | 894 | Effect.promise(async () => { |
| 895 | 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 | 897 | "http://127.0.0.1", |
| 898 | 898 | ); |
| 899 | 899 | url.searchParams.set("interactionId", pendingInteraction.value.id); |
| @@ -910,7 +910,7 @@ describe("executor-runtime", () => { · 10 unmodified lines | ||
| 910 | 910 | (handleRequest) => |
| 911 | 911 | Effect.promise(async () => { |
| 912 | 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 | 914 | "http://127.0.0.1", |
| 915 | 915 | ); |
| 916 | 916 | url.searchParams.set("interactionId", pendingInteraction.value.id); |
| @@ -978,12 +978,12 @@ describe("executor-runtime", () => { · 61 unmodified lines | ||
| 978 | 978 | it.scoped("loads a v1.2.3-style workspace artifact on startup", () => |
| 979 | 979 | Effect.gen(function* () { |
| 980 | 980 | const fs = yield* FileSystem.FileSystem; |
| 981 | − const workspaceRoot = yield* fs.makeTempDirectoryScoped({ | |
| 981 | + const scopeRoot = yield* fs.makeTempDirectoryScoped({ | |
| 982 | 982 | prefix: "executor-runtime-v123-", |
| 983 | 983 | }); |
| 984 | − const homeConfigPath = join(workspaceRoot, ".executor-home.jsonc"); | |
| 985 | − const homeStateDirectory = join(workspaceRoot, ".executor-home-state"); | |
| 986 | − const configDirectory = join(workspaceRoot, ".executor"); | |
| 984 | + const homeConfigPath = join(scopeRoot, ".executor-home.jsonc"); | |
| 985 | + const homeStateDirectory = join(scopeRoot, ".executor-home-state"); | |
| 986 | + const configDirectory = join(scopeRoot, ".executor"); | |
| 987 | 987 | const configPath = join(configDirectory, "executor.jsonc"); |
| 988 | 988 | const sourceId = SourceIdSchema.make("graphql"); |
| 989 | 989 | const now = Date.now(); |
| @@ -1010,13 +1010,13 @@ describe("executor-runtime", () => { · 20 unmodified lines | ||
| 1010 | 1010 | ); |
| 1011 | 1011 | |
| 1012 | 1012 | const context = yield* resolveLocalWorkspaceContext({ |
| 1013 | − workspaceRoot, | |
| 1013 | + workspaceRoot: scopeRoot, | |
| 1014 | 1014 | homeConfigPath, |
| 1015 | 1015 | homeStateDirectory, |
| 1016 | 1016 | }); |
| 1017 | 1017 | const installation = deriveLocalInstallation(context); |
| 1018 | 1018 | const source = yield* createSourceFromPayload({ |
| 1019 | − workspaceId: installation.workspaceId, | |
| 1019 | + scopeId: installation.scopeId, | |
| 1020 | 1020 | sourceId, |
| 1021 | 1021 | payload: { |
| 1022 | 1022 | name: "GraphQL API", |
| @@ -1108,7 +1108,7 @@ describe("executor-runtime", () => { · 85 unmodified lines | ||
| 1108 | 1108 | authArtifacts: [], |
| 1109 | 1109 | authLeases: [], |
| 1110 | 1110 | sourceOauthClients: [], |
| 1111 | − workspaceOauthClients: [], | |
| 1111 | + scopeOauthClients: [], | |
| 1112 | 1112 | providerAuthGrants: [], |
| 1113 | 1113 | sourceAuthSessions: [], |
| 1114 | 1114 | secretMaterials: [], |
| @@ -1145,7 +1145,7 @@ describe("executor-runtime", () => { · 30 unmodified lines | ||
| 1145 | 1145 | |
| 1146 | 1146 | const runtime = yield* Effect.acquireRelease( |
| 1147 | 1147 | createExecutorRuntime({ |
| 1148 | − workspaceRoot, | |
| 1148 | + workspaceRoot: scopeRoot, | |
| 1149 | 1149 | homeConfigPath, |
| 1150 | 1150 | homeStateDirectory, |
| 1151 | 1151 | }), |
| @@ -1154,11 +1154,11 @@ describe("executor-runtime", () => { · 2 unmodified lines | ||
| 1154 | 1154 | ); |
| 1155 | 1155 | |
| 1156 | 1156 | const inspection = yield* withExecutorApiClient( |
| 1157 | − { runtime, accountId: installation.accountId }, | |
| 1157 | + { runtime, actorScopeId: installation.actorScopeId }, | |
| 1158 | 1158 | (client) => |
| 1159 | 1159 | client.sources.inspection({ |
| 1160 | 1160 | path: { |
| 1161 | − workspaceId: installation.workspaceId, | |
| 1161 | + workspaceId: installation.scopeId, | |
| 1162 | 1162 | sourceId, |
| 1163 | 1163 | }, |
| 1164 | 1164 | }), |
| @@ -1179,13 +1179,13 @@ describe("executor-runtime", () => { · 14 unmodified lines | ||
| 1179 | 1179 | Effect.gen(function* () { |
| 1180 | 1180 | const fs = yield* FileSystem.FileSystem; |
| 1181 | 1181 | const openApiServer = yield* makeOpenApiSpecServer; |
| 1182 | − const workspaceRoot = yield* fs.makeTempDirectoryScoped({ | |
| 1182 | + const scopeRoot = yield* fs.makeTempDirectoryScoped({ | |
| 1183 | 1183 | prefix: "executor-runtime-startup-rebuild-", |
| 1184 | 1184 | }); |
| 1185 | − const homeConfigPath = join(workspaceRoot, ".executor-home.jsonc"); | |
| 1186 | − const homeStateDirectory = join(workspaceRoot, ".executor-home-state"); | |
| 1185 | + const homeConfigPath = join(scopeRoot, ".executor-home.jsonc"); | |
| 1186 | + const homeStateDirectory = join(scopeRoot, ".executor-home-state"); | |
| 1187 | 1187 | const context = yield* resolveLocalWorkspaceContext({ |
| 1188 | − workspaceRoot, | |
| 1188 | + workspaceRoot: scopeRoot, | |
| 1189 | 1189 | homeConfigPath, |
| 1190 | 1190 | homeStateDirectory, |
| 1191 | 1191 | }); |
| @@ -1193,7 +1193,7 @@ describe("executor-runtime", () => { · 1 unmodified line | ||
| 1193 | 1193 | const sourceId = SourceIdSchema.make("github"); |
| 1194 | 1194 | const now = Date.now(); |
| 1195 | 1195 | const source = yield* createSourceFromPayload({ |
| 1196 | − workspaceId: installation.workspaceId, | |
| 1196 | + scopeId: installation.scopeId, | |
| 1197 | 1197 | sourceId, |
| 1198 | 1198 | payload: { |
| 1199 | 1199 | name: "GitHub", |
| @@ -1251,7 +1251,7 @@ describe("executor-runtime", () => { · 51 unmodified lines | ||
| 1251 | 1251 | |
| 1252 | 1252 | const runtime = yield* Effect.acquireRelease( |
| 1253 | 1253 | createExecutorRuntime({ |
| 1254 | − workspaceRoot, | |
| 1254 | + workspaceRoot: scopeRoot, | |
| 1255 | 1255 | homeConfigPath, |
| 1256 | 1256 | homeStateDirectory, |
| 1257 | 1257 | }), |
| @@ -1266,11 +1266,11 @@ describe("executor-runtime", () => { · 8 unmodified lines | ||
| 1266 | 1266 | expect(rebuiltArtifact).not.toBeNull(); |
| 1267 | 1267 | |
| 1268 | 1268 | const inspection = yield* withExecutorApiClient( |
| 1269 | − { runtime, accountId: installation.accountId }, | |
| 1269 | + { runtime, actorScopeId: installation.actorScopeId }, | |
| 1270 | 1270 | (client) => |
| 1271 | 1271 | client.sources.inspection({ |
| 1272 | 1272 | path: { |
| 1273 | − workspaceId: installation.workspaceId, | |
| 1273 | + workspaceId: installation.scopeId, | |
| 1274 | 1274 | sourceId, |
| 1275 | 1275 | }, |
| 1276 | 1276 | }), |
| @@ -1290,7 +1290,7 @@ describe("executor-runtime", () => { · 13 unmodified lines | ||
| 1290 | 1290 | const now = Date.now(); |
| 1291 | 1291 | |
| 1292 | 1292 | const localSource = yield* createSourceFromPayload({ |
| 1293 | − workspaceId: installation.workspaceId, | |
| 1293 | + scopeId: installation.scopeId, | |
| 1294 | 1294 | sourceId, |
| 1295 | 1295 | payload: { |
| 1296 | 1296 | name: "Google Drive", |
| @@ -1314,18 +1314,18 @@ describe("executor-runtime", () => { · 17 unmodified lines | ||
| 1314 | 1314 | now, |
| 1315 | 1315 | }).pipe(Effect.orDie); |
| 1316 | 1316 | yield* persistSource(runtime.storage.executorState, localSource, { |
| 1317 | − actorAccountId: installation.accountId, | |
| 1317 | + actorScopeId: installation.actorScopeId, | |
| 1318 | 1318 | }).pipe( |
| 1319 | 1319 | (effect) => provideExecutorRuntime(effect, runtime), |
| 1320 | 1320 | Effect.orDie, |
| 1321 | 1321 | ); |
| 1322 | 1322 | |
| 1323 | 1323 | const inspection = yield* withExecutorApiClient( |
| 1324 | − { runtime, accountId: installation.accountId }, | |
| 1324 | + { runtime, actorScopeId: installation.actorScopeId }, | |
| 1325 | 1325 | (client) => |
| 1326 | 1326 | client.sources.inspection({ |
| 1327 | 1327 | path: { |
| 1328 | − workspaceId: installation.workspaceId, | |
| 1328 | + workspaceId: installation.scopeId, | |
| 1329 | 1329 | sourceId, |
| 1330 | 1330 | }, |
| 1331 | 1331 | }), |
| @@ -1348,7 +1348,7 @@ describe("executor-runtime", () => { · 16 unmodified lines | ||
| 1348 | 1348 | const now = Date.now(); |
| 1349 | 1349 | |
| 1350 | 1350 | const localSource = yield* createSourceFromPayload({ |
| 1351 | − workspaceId: installation.workspaceId, | |
| 1351 | + scopeId: installation.scopeId, | |
| 1352 | 1352 | sourceId, |
| 1353 | 1353 | payload: { |
| 1354 | 1354 | name: "Google Drive", |
| @@ -1372,7 +1372,7 @@ describe("executor-runtime", () => { · 17 unmodified lines | ||
| 1372 | 1372 | now, |
| 1373 | 1373 | }).pipe(Effect.orDie); |
| 1374 | 1374 | yield* persistSource(runtime.storage.executorState, localSource, { |
| 1375 | − actorAccountId: installation.accountId, | |
| 1375 | + actorScopeId: installation.actorScopeId, | |
| 1376 | 1376 | }).pipe( |
| 1377 | 1377 | (effect) => provideExecutorRuntime(effect, runtime), |
| 1378 | 1378 | Effect.orDie, |
| @@ -1380,11 +1380,11 @@ describe("executor-runtime", () => { · 1 unmodified line | ||
| 1380 | 1380 | |
| 1381 | 1381 | const error = yield* expectLeft( |
| 1382 | 1382 | withExecutorApiClient( |
| 1383 | − { runtime, accountId: installation.accountId }, | |
| 1383 | + { runtime, actorScopeId: installation.actorScopeId }, | |
| 1384 | 1384 | (client) => |
| 1385 | 1385 | client.sources.inspection({ |
| 1386 | 1386 | path: { |
| 1387 | − workspaceId: installation.workspaceId, | |
| 1387 | + workspaceId: installation.scopeId, | |
| 1388 | 1388 | sourceId, |
| 1389 | 1389 | }, |
| 1390 | 1390 | }), |
| @@ -1415,8 +1415,8 @@ describe("executor-runtime", () => { · 24 unmodified lines | ||
| 1415 | 1415 | |
| 1416 | 1416 | yield* runtime.storage.executorState.executions.insert({ |
| 1417 | 1417 | id: executionId, |
| 1418 | − workspaceId: installation.workspaceId, | |
| 1419 | − createdByAccountId: installation.accountId, | |
| 1418 | + scopeId: installation.scopeId, | |
| 1419 | + createdByScopeId: installation.actorScopeId, | |
| 1420 | 1420 | status: "running", |
| 1421 | 1421 | code: "return await tools.executor.sources.add(...)", |
| 1422 | 1422 | resultJson: null, |
| @@ -1429,7 +1429,7 @@ describe("executor-runtime", () => { · 6 unmodified lines | ||
| 1429 | 1429 | }); |
| 1430 | 1430 | |
| 1431 | 1431 | const localSource = yield* createSourceFromPayload({ |
| 1432 | − workspaceId: installation.workspaceId, | |
| 1432 | + scopeId: installation.scopeId, | |
| 1433 | 1433 | sourceId, |
| 1434 | 1434 | payload: { |
| 1435 | 1435 | name: "GitHub", |
| @@ -1449,7 +1449,7 @@ describe("executor-runtime", () => { · 13 unmodified lines | ||
| 1449 | 1449 | now, |
| 1450 | 1450 | }).pipe(Effect.orDie); |
| 1451 | 1451 | yield* persistSource(runtime.storage.executorState, localSource, { |
| 1452 | − actorAccountId: installation.accountId, | |
| 1452 | + actorScopeId: installation.actorScopeId, | |
| 1453 | 1453 | }).pipe( |
| 1454 | 1454 | (effect) => provideExecutorRuntime(effect, runtime), |
| 1455 | 1455 | Effect.orDie, |
| @@ -1471,13 +1471,13 @@ describe("executor-runtime", () => { · 15 unmodified lines | ||
| 1471 | 1471 | endpoint: "https://api.github.com", |
| 1472 | 1472 | specUrl: "https://example.com/github-openapi.yaml", |
| 1473 | 1473 | name: "GitHub", |
| 1474 | − workspaceId: installation.workspaceId, | |
| 1474 | + scopeId: installation.scopeId, | |
| 1475 | 1475 | sourceId, |
| 1476 | 1476 | }, |
| 1477 | 1477 | elicitation: { |
| 1478 | 1478 | mode: "url", |
| 1479 | 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 | 1481 | elicitationId: interactionSuffix, |
| 1482 | 1482 | }, |
| 1483 | 1483 | }); |
| @@ -1505,7 +1505,7 @@ describe("executor-runtime", () => { · 21 unmodified lines | ||
| 1505 | 1505 | assertTrue(Option.isSome(pendingInteraction)); |
| 1506 | 1506 | |
| 1507 | 1507 | const submitted = yield* submitSourceCredentialInteraction({ |
| 1508 | − workspaceId: installation.workspaceId, | |
| 1508 | + scopeId: installation.scopeId, | |
| 1509 | 1509 | sourceId, |
| 1510 | 1510 | interactionId: pendingInteraction.value.id, |
| 1511 | 1511 | action: "continue", |
| @@ -1538,7 +1538,7 @@ describe("executor-runtime", () => { · 26 unmodified lines | ||
| 1538 | 1538 | const executionId = ExecutionIdSchema.make( |
| 1539 | 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 | 1542 | const sourceId = SourceIdSchema.make("graphql_api"); |
| 1543 | 1543 | const now = Date.now(); |
| 1544 | 1544 | const decoded = decodeSourceCredentialInteraction({ |
| @@ -1555,7 +1555,7 @@ describe("executor-runtime", () => { · 10 unmodified lines | ||
| 1555 | 1555 | endpoint: "https://example.com/graphql", |
| 1556 | 1556 | name: "GraphQL API", |
| 1557 | 1557 | namespace: "graphql", |
| 1558 | − workspaceId, | |
| 1558 | + scopeId, | |
| 1559 | 1559 | sourceId, |
| 1560 | 1560 | }, |
| 1561 | 1561 | elicitation: { |
| @@ -1570,7 +1570,7 @@ describe("executor-runtime", () => { · 8 unmodified lines | ||
| 1570 | 1570 | }); |
| 1571 | 1571 | |
| 1572 | 1572 | expect(decoded).not.toBeNull(); |
| 1573 | − expect(decoded?.workspaceId).toBe(workspaceId); | |
| 1573 | + expect(decoded?.scopeId).toBe(scopeId); | |
| 1574 | 1574 | expect(decoded?.sourceId).toBe(sourceId); |
| 1575 | 1575 | expect(decoded?.message).toContain("GraphQL API"); |
| 1576 | 1576 | }), |
| @@ -1589,7 +1589,7 @@ describe("executor-runtime", () => { · 12 unmodified lines | ||
| 1589 | 1589 | (client) => |
| 1590 | 1590 | client.sources.createWorkspaceOauthClient({ |
| 1591 | 1591 | path: { |
| 1592 | − workspaceId: installation.workspaceId, | |
| 1592 | + workspaceId: installation.scopeId, | |
| 1593 | 1593 | }, |
| 1594 | 1594 | payload: { |
| 1595 | 1595 | providerKey: "google_workspace", |
| @@ -1615,8 +1615,8 @@ describe("executor-runtime", () => { · 19 unmodified lines | ||
| 1615 | 1615 | ); |
| 1616 | 1616 | yield* runtime.storage.executorState.providerAuthGrants.upsert({ |
| 1617 | 1617 | id: grantId, |
| 1618 | − workspaceId: installation.workspaceId, | |
| 1619 | − actorAccountId: installation.accountId, | |
| 1618 | + scopeId: installation.scopeId, | |
| 1619 | + actorScopeId: installation.actorScopeId, | |
| 1620 | 1620 | providerKey: "google_workspace", |
| 1621 | 1621 | oauthClientId: oauthClient.id, |
| 1622 | 1622 | tokenEndpoint: googleServer.tokenEndpoint, |
| @@ -1642,11 +1642,11 @@ describe("executor-runtime", () => { · 19 unmodified lines | ||
| 1642 | 1642 | const result = yield* withExecutorApiClient({ runtime }, (client) => |
| 1643 | 1643 | client.sources.connect({ |
| 1644 | 1644 | path: { |
| 1645 | − workspaceId: installation.workspaceId, | |
| 1645 | + workspaceId: installation.scopeId, | |
| 1646 | 1646 | }, |
| 1647 | 1647 | payload: { |
| 1648 | 1648 | kind: "google_discovery", |
| 1649 | − workspaceOauthClientId: oauthClient.id, | |
| 1649 | + scopeOauthClientId: oauthClient.id, | |
| 1650 | 1650 | service: "drive", |
| 1651 | 1651 | version: "v3", |
| 1652 | 1652 | discoveryUrl: googleServer.discoveryUrl({ |
| @@ -1698,7 +1698,7 @@ describe("executor-runtime", () => { · 45 unmodified lines | ||
| 1698 | 1698 | (client) => |
| 1699 | 1699 | client.sources.createWorkspaceOauthClient({ |
| 1700 | 1700 | path: { |
| 1701 | − workspaceId: installation.workspaceId, | |
| 1701 | + workspaceId: installation.scopeId, | |
| 1702 | 1702 | }, |
| 1703 | 1703 | payload: { |
| 1704 | 1704 | providerKey: "google_workspace", |
| @@ -1714,11 +1714,11 @@ describe("executor-runtime", () => { · 9 unmodified lines | ||
| 1714 | 1714 | const result = yield* withExecutorApiClient({ runtime }, (client) => |
| 1715 | 1715 | client.sources.connect({ |
| 1716 | 1716 | path: { |
| 1717 | − workspaceId: installation.workspaceId, | |
| 1717 | + workspaceId: installation.scopeId, | |
| 1718 | 1718 | }, |
| 1719 | 1719 | payload: { |
| 1720 | 1720 | kind: "google_discovery", |
| 1721 | − workspaceOauthClientId: oauthClient.id, | |
| 1721 | + scopeOauthClientId: oauthClient.id, | |
| 1722 | 1722 | service: "gmail", |
| 1723 | 1723 | version: "v1", |
| 1724 | 1724 | discoveryUrl: googleServer.discoveryUrl({ |
| @@ -1745,7 +1745,7 @@ describe("executor-runtime", () => { · 20 unmodified lines | ||
| 1745 | 1745 | ); |
| 1746 | 1746 | expect(redirectUri).not.toBeNull(); |
| 1747 | 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 | 1750 | expect(result.source.status).toBe("auth_required"); |
| 1751 | 1751 | }), |
| @@ -1765,7 +1765,7 @@ describe("executor-runtime", () => { · 13 unmodified lines | ||
| 1765 | 1765 | (client) => |
| 1766 | 1766 | client.sources.createWorkspaceOauthClient({ |
| 1767 | 1767 | path: { |
| 1768 | − workspaceId: installation.workspaceId, | |
| 1768 | + workspaceId: installation.scopeId, | |
| 1769 | 1769 | }, |
| 1770 | 1770 | payload: { |
| 1771 | 1771 | providerKey: "google_workspace", |
| @@ -1791,8 +1791,8 @@ describe("executor-runtime", () => { · 19 unmodified lines | ||
| 1791 | 1791 | ); |
| 1792 | 1792 | yield* runtime.storage.executorState.providerAuthGrants.upsert({ |
| 1793 | 1793 | id: grantId, |
| 1794 | − workspaceId: installation.workspaceId, | |
| 1795 | − actorAccountId: installation.accountId, | |
| 1794 | + scopeId: installation.scopeId, | |
| 1795 | + actorScopeId: installation.actorScopeId, | |
| 1796 | 1796 | providerKey: "google_workspace", |
| 1797 | 1797 | oauthClientId: oauthClient.id, |
| 1798 | 1798 | tokenEndpoint: googleServer.tokenEndpoint, |
| @@ -1822,10 +1822,10 @@ describe("executor-runtime", () => { · 23 unmodified lines | ||
| 1822 | 1822 | const result = yield* withExecutorApiClient({ runtime }, (client) => |
| 1823 | 1823 | client.sources.connectBatch({ |
| 1824 | 1824 | path: { |
| 1825 | − workspaceId: installation.workspaceId, | |
| 1825 | + workspaceId: installation.scopeId, | |
| 1826 | 1826 | }, |
| 1827 | 1827 | payload: { |
| 1828 | − workspaceOauthClientId: oauthClient.id, | |
| 1828 | + scopeOauthClientId: oauthClient.id, | |
| 1829 | 1829 | sources: [ |
| 1830 | 1830 | { |
| 1831 | 1831 | service: "gmail", |
| @@ -1894,7 +1894,7 @@ describe("executor-runtime", () => { · 62 unmodified lines | ||
| 1894 | 1894 | (client) => |
| 1895 | 1895 | client.sources.createWorkspaceOauthClient({ |
| 1896 | 1896 | path: { |
| 1897 | − workspaceId: installation.workspaceId, | |
| 1897 | + workspaceId: installation.scopeId, | |
| 1898 | 1898 | }, |
| 1899 | 1899 | payload: { |
| 1900 | 1900 | providerKey: "google_workspace", |
| @@ -1910,10 +1910,10 @@ describe("executor-runtime", () => { · 9 unmodified lines | ||
| 1910 | 1910 | const result = yield* withExecutorApiClient({ runtime }, (client) => |
| 1911 | 1911 | client.sources.connectBatch({ |
| 1912 | 1912 | path: { |
| 1913 | − workspaceId: installation.workspaceId, | |
| 1913 | + workspaceId: installation.scopeId, | |
| 1914 | 1914 | }, |
| 1915 | 1915 | payload: { |
| 1916 | − workspaceOauthClientId: oauthClient.id, | |
| 1916 | + scopeOauthClientId: oauthClient.id, | |
| 1917 | 1917 | sources: [ |
| 1918 | 1918 | { |
| 1919 | 1919 | service: "gmail", |
| @@ -1939,7 +1939,7 @@ describe("executor-runtime", () => { · 19 unmodified lines | ||
| 1939 | 1939 | |
| 1940 | 1940 | expect(redirectUri).not.toBeNull(); |
| 1941 | 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 | 1945 | 60_000, |
| @@ -1958,7 +1958,7 @@ describe("executor-runtime", () => { · 12 unmodified lines | ||
| 1958 | 1958 | (client) => |
| 1959 | 1959 | client.sources.createWorkspaceOauthClient({ |
| 1960 | 1960 | path: { |
| 1961 | − workspaceId: installation.workspaceId, | |
| 1961 | + workspaceId: installation.scopeId, | |
| 1962 | 1962 | }, |
| 1963 | 1963 | payload: { |
| 1964 | 1964 | providerKey: "google_workspace", |
| @@ -2001,8 +2001,8 @@ describe("executor-runtime", () => { · 36 unmodified lines | ||
| 2001 | 2001 | ); |
| 2002 | 2002 | yield* runtime.storage.executorState.providerAuthGrants.upsert({ |
| 2003 | 2003 | id: grantId, |
| 2004 | − workspaceId: installation.workspaceId, | |
| 2005 | − actorAccountId: installation.accountId, | |
| 2004 | + scopeId: installation.scopeId, | |
| 2005 | + actorScopeId: installation.actorScopeId, | |
| 2006 | 2006 | providerKey: "google_workspace", |
| 2007 | 2007 | oauthClientId: oauthClient.id, |
| 2008 | 2008 | tokenEndpoint: googleServer.tokenEndpoint, |
| @@ -2026,11 +2026,11 @@ describe("executor-runtime", () => { · 17 unmodified lines | ||
| 2026 | 2026 | const state = `provider-state-${crypto.randomUUID()}`; |
| 2027 | 2027 | yield* runtime.storage.executorState.sourceAuthSessions.upsert({ |
| 2028 | 2028 | id: sessionId, |
| 2029 | − workspaceId: installation.workspaceId, | |
| 2029 | + scopeId: installation.scopeId, | |
| 2030 | 2030 | sourceId: SourceIdSchema.make( |
| 2031 | 2031 | `oauth_provider_${crypto.randomUUID()}`, |
| 2032 | 2032 | ), |
| 2033 | − actorAccountId: installation.accountId, | |
| 2033 | + actorScopeId: installation.actorScopeId, | |
| 2034 | 2034 | credentialSlot: "runtime", |
| 2035 | 2035 | executionId: null, |
| 2036 | 2036 | interactionId: null, |
| @@ -2083,7 +2083,7 @@ describe("executor-runtime", () => { · 46 unmodified lines | ||
| 2083 | 2083 | (client) => |
| 2084 | 2084 | client.sources.providerOauthComplete({ |
| 2085 | 2085 | path: { |
| 2086 | − workspaceId: installation.workspaceId, | |
| 2086 | + workspaceId: installation.scopeId, | |
| 2087 | 2087 | }, |
| 2088 | 2088 | urlParams: { |
| 2089 | 2089 | state, |
| @@ -2111,7 +2111,7 @@ describe("executor-runtime", () => { · 21 unmodified lines | ||
| 2111 | 2111 | (client) => |
| 2112 | 2112 | client.sources.get({ |
| 2113 | 2113 | path: { |
| 2114 | − workspaceId: installation.workspaceId, | |
| 2114 | + workspaceId: installation.scopeId, | |
| 2115 | 2115 | sourceId: source.id, |
| 2116 | 2116 | }, |
| 2117 | 2117 | }), |
| @@ -2148,14 +2148,14 @@ describe("executor-runtime", () => { · 30 unmodified lines | ||
| 2148 | 2148 | Effect.gen(function* () { |
| 2149 | 2149 | const runtime = yield* makeRuntime; |
| 2150 | 2150 | const installation = runtime.localInstallation; |
| 2151 | − const oauthClientId = WorkspaceOauthClientIdSchema.make( | |
| 2151 | + const oauthClientId = ScopeOauthClientIdSchema.make( | |
| 2152 | 2152 | `ws_oauth_client_${crypto.randomUUID()}`, |
| 2153 | 2153 | ); |
| 2154 | 2154 | const refreshSecretId = "sec_google_refresh_orphan"; |
| 2155 | 2155 | |
| 2156 | − yield* runtime.storage.executorState.workspaceOauthClients.upsert({ | |
| 2156 | + yield* runtime.storage.executorState.scopeOauthClients.upsert({ | |
| 2157 | 2157 | id: oauthClientId, |
| 2158 | − workspaceId: installation.workspaceId, | |
| 2158 | + scopeId: installation.scopeId, | |
| 2159 | 2159 | providerKey: "google_workspace", |
| 2160 | 2160 | label: "Local Google Workspace Client", |
| 2161 | 2161 | clientId: "google-client-id", |
| @@ -2177,8 +2177,8 @@ describe("executor-runtime", () => { · 15 unmodified lines | ||
| 2177 | 2177 | ); |
| 2178 | 2178 | yield* runtime.storage.executorState.providerAuthGrants.upsert({ |
| 2179 | 2179 | id: grantId, |
| 2180 | − workspaceId: installation.workspaceId, | |
| 2181 | − actorAccountId: installation.accountId, | |
| 2180 | + scopeId: installation.scopeId, | |
| 2181 | + actorScopeId: installation.actorScopeId, | |
| 2182 | 2182 | providerKey: "google_workspace", |
| 2183 | 2183 | oauthClientId, |
| 2184 | 2184 | tokenEndpoint: "https://example.test/oauth/token", |
| @@ -2217,7 +2217,7 @@ describe("executor-runtime", () => { · 32 unmodified lines | ||
| 2217 | 2217 | const removed = yield* withExecutorApiClient({ runtime }, (client) => |
| 2218 | 2218 | client.sources.remove({ |
| 2219 | 2219 | path: { |
| 2220 | − workspaceId: installation.workspaceId, | |
| 2220 | + workspaceId: installation.scopeId, | |
| 2221 | 2221 | sourceId: source.id, |
| 2222 | 2222 | }, |
| 2223 | 2223 | }), |
| @@ -2238,14 +2238,14 @@ describe("executor-runtime", () => { · 14 unmodified lines | ||
| 2238 | 2238 | Effect.gen(function* () { |
| 2239 | 2239 | const runtime = yield* makeRuntime; |
| 2240 | 2240 | const installation = runtime.localInstallation; |
| 2241 | − const oauthClientId = WorkspaceOauthClientIdSchema.make( | |
| 2241 | + const oauthClientId = ScopeOauthClientIdSchema.make( | |
| 2242 | 2242 | `ws_oauth_client_${crypto.randomUUID()}`, |
| 2243 | 2243 | ); |
| 2244 | 2244 | const refreshSecretId = "sec_google_refresh_revoke"; |
| 2245 | 2245 | |
| 2246 | − yield* runtime.storage.executorState.workspaceOauthClients.upsert({ | |
| 2246 | + yield* runtime.storage.executorState.scopeOauthClients.upsert({ | |
| 2247 | 2247 | id: oauthClientId, |
| 2248 | − workspaceId: installation.workspaceId, | |
| 2248 | + scopeId: installation.scopeId, | |
| 2249 | 2249 | providerKey: "google_workspace", |
| 2250 | 2250 | label: "Local Google Workspace Client", |
| 2251 | 2251 | clientId: "google-client-id", |
| @@ -2267,8 +2267,8 @@ describe("executor-runtime", () => { · 15 unmodified lines | ||
| 2267 | 2267 | ); |
| 2268 | 2268 | yield* runtime.storage.executorState.providerAuthGrants.upsert({ |
| 2269 | 2269 | id: grantId, |
| 2270 | − workspaceId: installation.workspaceId, | |
| 2271 | − actorAccountId: installation.accountId, | |
| 2270 | + scopeId: installation.scopeId, | |
| 2271 | + actorScopeId: installation.actorScopeId, | |
| 2272 | 2272 | providerKey: "google_workspace", |
| 2273 | 2273 | oauthClientId, |
| 2274 | 2274 | tokenEndpoint: "https://example.test/oauth/token", |
| @@ -2324,7 +2324,7 @@ describe("executor-runtime", () => { · 49 unmodified lines | ||
| 2324 | 2324 | const removed = yield* withExecutorApiClient({ runtime }, (client) => |
| 2325 | 2325 | client.sources.removeProviderAuthGrant({ |
| 2326 | 2326 | path: { |
| 2327 | − workspaceId: installation.workspaceId, | |
| 2327 | + workspaceId: installation.scopeId, | |
| 2328 | 2328 | grantId, |
| 2329 | 2329 | }, |
| 2330 | 2330 | }), |
| @@ -2347,7 +2347,7 @@ describe("executor-runtime", () => { · 16 unmodified lines | ||
| 2347 | 2347 | (client) => |
| 2348 | 2348 | client.sources.get({ |
| 2349 | 2349 | path: { |
| 2350 | − workspaceId: installation.workspaceId, | |
| 2350 | + workspaceId: installation.scopeId, | |
| 2351 | 2351 | sourceId: driveSource.id, |
| 2352 | 2352 | }, |
| 2353 | 2353 | }), |
| @@ -2357,7 +2357,7 @@ describe("executor-runtime", () => { · 3 unmodified lines | ||
| 2357 | 2357 | (client) => |
| 2358 | 2358 | client.sources.get({ |
| 2359 | 2359 | path: { |
| 2360 | − workspaceId: installation.workspaceId, | |
| 2360 | + workspaceId: installation.scopeId, | |
| 2361 | 2361 | sourceId: gmailSource.id, |
| 2362 | 2362 | }, |
| 2363 | 2363 | }), |
| @@ -10,8 +10,8 @@ import type { · 9 unmodified lines | ||
| 10 | 10 | ProviderAuthGrant, |
| 11 | 11 | SecretMaterial, |
| 12 | 12 | SourceAuthSession, |
| 13 | − WorkspaceOauthClient, | |
| 14 | − WorkspaceSourceOauthClient, | |
| 13 | + ScopeOauthClient, | |
| 14 | + ScopedSourceOauthClient, | |
| 15 | 15 | } from "#schema"; |
| 16 | 16 | |
| 17 | 17 | type SecretMaterialSummary = { |
| @@ -25,28 +25,28 @@ type SecretMaterialSummary = { · 7 unmodified lines | ||
| 25 | 25 | |
| 26 | 26 | export type ExecutorStateStoreShape = { |
| 27 | 27 | authArtifacts: { |
| 28 | − listByWorkspaceId: ( | |
| 29 | − workspaceId: AuthArtifact["workspaceId"], | |
| 28 | + listByScopeId: ( | |
| 29 | + scopeId: AuthArtifact["scopeId"], | |
| 30 | 30 | ) => Effect.Effect<readonly AuthArtifact[], Error, never>; |
| 31 | − listByWorkspaceAndSourceId: (input: { | |
| 32 | − workspaceId: AuthArtifact["workspaceId"]; | |
| 31 | + listByScopeAndSourceId: (input: { | |
| 32 | + scopeId: AuthArtifact["scopeId"]; | |
| 33 | 33 | sourceId: AuthArtifact["sourceId"]; |
| 34 | 34 | }) => Effect.Effect<readonly AuthArtifact[], Error, never>; |
| 35 | − getByWorkspaceSourceAndActor: (input: { | |
| 36 | − workspaceId: AuthArtifact["workspaceId"]; | |
| 35 | + getByScopeSourceAndActor: (input: { | |
| 36 | + scopeId: AuthArtifact["scopeId"]; | |
| 37 | 37 | sourceId: AuthArtifact["sourceId"]; |
| 38 | − actorAccountId: AuthArtifact["actorAccountId"]; | |
| 38 | + actorScopeId: AuthArtifact["actorScopeId"]; | |
| 39 | 39 | slot: AuthArtifact["slot"]; |
| 40 | 40 | }) => Effect.Effect<import("effect/Option").Option<AuthArtifact>, Error, never>; |
| 41 | 41 | upsert: (artifact: AuthArtifact) => Effect.Effect<void, Error, never>; |
| 42 | − removeByWorkspaceSourceAndActor: (input: { | |
| 43 | − workspaceId: AuthArtifact["workspaceId"]; | |
| 42 | + removeByScopeSourceAndActor: (input: { | |
| 43 | + scopeId: AuthArtifact["scopeId"]; | |
| 44 | 44 | sourceId: AuthArtifact["sourceId"]; |
| 45 | − actorAccountId: AuthArtifact["actorAccountId"]; | |
| 45 | + actorScopeId: AuthArtifact["actorScopeId"]; | |
| 46 | 46 | slot?: AuthArtifact["slot"]; |
| 47 | 47 | }) => Effect.Effect<boolean, Error, never>; |
| 48 | − removeByWorkspaceAndSourceId: (input: { | |
| 49 | − workspaceId: AuthArtifact["workspaceId"]; | |
| 48 | + removeByScopeAndSourceId: (input: { | |
| 49 | + scopeId: AuthArtifact["scopeId"]; | |
| 50 | 50 | sourceId: AuthArtifact["sourceId"]; |
| 51 | 51 | }) => Effect.Effect<number, Error, never>; |
| 52 | 52 | }; |
| @@ -61,41 +61,41 @@ export type ExecutorStateStoreShape = { · 8 unmodified lines | ||
| 61 | 61 | ) => Effect.Effect<boolean, Error, never>; |
| 62 | 62 | }; |
| 63 | 63 | sourceOauthClients: { |
| 64 | − getByWorkspaceSourceAndProvider: (input: { | |
| 65 | − workspaceId: WorkspaceSourceOauthClient["workspaceId"]; | |
| 66 | − sourceId: WorkspaceSourceOauthClient["sourceId"]; | |
| 64 | + getByScopeSourceAndProvider: (input: { | |
| 65 | + scopeId: ScopedSourceOauthClient["scopeId"]; | |
| 66 | + sourceId: ScopedSourceOauthClient["sourceId"]; | |
| 67 | 67 | providerKey: string; |
| 68 | 68 | }) => Effect.Effect< |
| 69 | − import("effect/Option").Option<WorkspaceSourceOauthClient>, | |
| 69 | + import("effect/Option").Option<ScopedSourceOauthClient>, | |
| 70 | 70 | Error, |
| 71 | 71 | never |
| 72 | 72 | >; |
| 73 | 73 | upsert: ( |
| 74 | − oauthClient: WorkspaceSourceOauthClient, | |
| 74 | + oauthClient: ScopedSourceOauthClient, | |
| 75 | 75 | ) => Effect.Effect<void, Error, never>; |
| 76 | − removeByWorkspaceAndSourceId: (input: { | |
| 77 | − workspaceId: WorkspaceSourceOauthClient["workspaceId"]; | |
| 78 | − sourceId: WorkspaceSourceOauthClient["sourceId"]; | |
| 76 | + removeByScopeAndSourceId: (input: { | |
| 77 | + scopeId: ScopedSourceOauthClient["scopeId"]; | |
| 78 | + sourceId: ScopedSourceOauthClient["sourceId"]; | |
| 79 | 79 | }) => Effect.Effect<number, Error, never>; |
| 80 | 80 | }; |
| 81 | − workspaceOauthClients: { | |
| 82 | − listByWorkspaceAndProvider: (input: { | |
| 83 | − workspaceId: WorkspaceOauthClient["workspaceId"]; | |
| 81 | + scopeOauthClients: { | |
| 82 | + listByScopeAndProvider: (input: { | |
| 83 | + scopeId: ScopeOauthClient["scopeId"]; | |
| 84 | 84 | providerKey: string; |
| 85 | − }) => Effect.Effect<readonly WorkspaceOauthClient[], Error, never>; | |
| 85 | + }) => Effect.Effect<readonly ScopeOauthClient[], Error, never>; | |
| 86 | 86 | getById: ( |
| 87 | − id: WorkspaceOauthClient["id"], | |
| 88 | − ) => Effect.Effect<import("effect/Option").Option<WorkspaceOauthClient>, Error, never>; | |
| 89 | − upsert: (oauthClient: WorkspaceOauthClient) => Effect.Effect<void, Error, never>; | |
| 90 | − removeById: (id: WorkspaceOauthClient["id"]) => Effect.Effect<boolean, Error, never>; | |
| 87 | + id: ScopeOauthClient["id"], | |
| 88 | + ) => Effect.Effect<import("effect/Option").Option<ScopeOauthClient>, Error, never>; | |
| 89 | + upsert: (oauthClient: ScopeOauthClient) => Effect.Effect<void, Error, never>; | |
| 90 | + removeById: (id: ScopeOauthClient["id"]) => Effect.Effect<boolean, Error, never>; | |
| 91 | 91 | }; |
| 92 | 92 | providerAuthGrants: { |
| 93 | − listByWorkspaceId: ( | |
| 94 | − workspaceId: ProviderAuthGrant["workspaceId"], | |
| 93 | + listByScopeId: ( | |
| 94 | + scopeId: ProviderAuthGrant["scopeId"], | |
| 95 | 95 | ) => Effect.Effect<readonly ProviderAuthGrant[], Error, never>; |
| 96 | − listByWorkspaceActorAndProvider: (input: { | |
| 97 | − workspaceId: ProviderAuthGrant["workspaceId"]; | |
| 98 | − actorAccountId: ProviderAuthGrant["actorAccountId"]; | |
| 96 | + listByScopeActorAndProvider: (input: { | |
| 97 | + scopeId: ProviderAuthGrant["scopeId"]; | |
| 98 | + actorScopeId: ProviderAuthGrant["actorScopeId"]; | |
| 99 | 99 | providerKey: string; |
| 100 | 100 | }) => Effect.Effect<readonly ProviderAuthGrant[], Error, never>; |
| 101 | 101 | getById: ( |
| @@ -106,8 +106,8 @@ export type ExecutorStateStoreShape = { · 4 unmodified lines | ||
| 106 | 106 | }; |
| 107 | 107 | sourceAuthSessions: { |
| 108 | 108 | listAll: () => Effect.Effect<readonly SourceAuthSession[], Error, never>; |
| 109 | − listByWorkspaceId: ( | |
| 110 | − workspaceId: SourceAuthSession["workspaceId"], | |
| 109 | + listByScopeId: ( | |
| 110 | + scopeId: SourceAuthSession["scopeId"], | |
| 111 | 111 | ) => Effect.Effect<readonly SourceAuthSession[], Error, never>; |
| 112 | 112 | getById: ( |
| 113 | 113 | id: SourceAuthSession["id"], |
| @@ -115,10 +115,10 @@ export type ExecutorStateStoreShape = { · 1 unmodified line | ||
| 115 | 115 | getByState: ( |
| 116 | 116 | state: SourceAuthSession["state"], |
| 117 | 117 | ) => Effect.Effect<import("effect/Option").Option<SourceAuthSession>, Error, never>; |
| 118 | − getPendingByWorkspaceSourceAndActor: (input: { | |
| 119 | − workspaceId: SourceAuthSession["workspaceId"]; | |
| 118 | + getPendingByScopeSourceAndActor: (input: { | |
| 119 | + scopeId: SourceAuthSession["scopeId"]; | |
| 120 | 120 | sourceId: SourceAuthSession["sourceId"]; |
| 121 | − actorAccountId: SourceAuthSession["actorAccountId"]; | |
| 121 | + actorScopeId: SourceAuthSession["actorScopeId"]; | |
| 122 | 122 | credentialSlot?: SourceAuthSession["credentialSlot"]; |
| 123 | 123 | }) => Effect.Effect< |
| 124 | 124 | import("effect/Option").Option<SourceAuthSession>, |
| @@ -129,12 +129,12 @@ export type ExecutorStateStoreShape = { · 4 unmodified lines | ||
| 129 | 129 | update: ( |
| 130 | 130 | id: SourceAuthSession["id"], |
| 131 | 131 | patch: Partial< |
| 132 | − Omit<SourceAuthSession, "id" | "workspaceId" | "sourceId" | "createdAt"> | |
| 132 | + Omit<SourceAuthSession, "id" | "scopeId" | "sourceId" | "createdAt"> | |
| 133 | 133 | >, |
| 134 | 134 | ) => Effect.Effect<import("effect/Option").Option<SourceAuthSession>, Error, never>; |
| 135 | 135 | upsert: (session: SourceAuthSession) => Effect.Effect<void, Error, never>; |
| 136 | − removeByWorkspaceAndSourceId: ( | |
| 137 | − workspaceId: SourceAuthSession["workspaceId"], | |
| 136 | + removeByScopeAndSourceId: ( | |
| 137 | + scopeId: SourceAuthSession["scopeId"], | |
| 138 | 138 | sourceId: SourceAuthSession["sourceId"], |
| 139 | 139 | ) => Effect.Effect<boolean, Error, never>; |
| 140 | 140 | }; |
| @@ -158,15 +158,15 @@ export type ExecutorStateStoreShape = { · 17 unmodified lines | ||
| 158 | 158 | getById: ( |
| 159 | 159 | executionId: Execution["id"], |
| 160 | 160 | ) => Effect.Effect<import("effect/Option").Option<Execution>, Error, never>; |
| 161 | − getByWorkspaceAndId: ( | |
| 162 | − workspaceId: Execution["workspaceId"], | |
| 161 | + getByScopeAndId: ( | |
| 162 | + scopeId: Execution["scopeId"], | |
| 163 | 163 | executionId: Execution["id"], |
| 164 | 164 | ) => Effect.Effect<import("effect/Option").Option<Execution>, Error, never>; |
| 165 | 165 | insert: (execution: Execution) => Effect.Effect<void, Error, never>; |
| 166 | 166 | update: ( |
| 167 | 167 | executionId: Execution["id"], |
| 168 | 168 | patch: Partial< |
| 169 | − Omit<Execution, "id" | "workspaceId" | "createdByAccountId" | "createdAt"> | |
| 169 | + Omit<Execution, "id" | "scopeId" | "createdByScopeId" | "createdAt"> | |
| 170 | 170 | >, |
| 171 | 171 | ) => Effect.Effect<import("effect/Option").Option<Execution>, Error, never>; |
| 172 | 172 | }; |
| @@ -3,30 +3,56 @@ import { · 2 unmodified lines | ||
| 3 | 3 | makeToolInvokerFromTools, |
| 4 | 4 | type ToolMap, |
| 5 | 5 | } from "@executor/codemode-core"; |
| 6 | −import { clearAllMcpConnectionPools } from "@executor/source-mcp"; | |
| 7 | −import type { LocalInstallation } from "#schema"; | |
| 6 | +import { | |
| 7 | + clearAllMcpConnectionPools, | |
| 8 | +} from "@executor/source-mcp"; | |
| 9 | +import type { | |
| 10 | + LocalInstallation, | |
| 11 | +} from "#schema"; | |
| 8 | 12 | import * as Effect from "effect/Effect"; |
| 9 | 13 | import * as Layer from "effect/Layer"; |
| 10 | 14 | import * as ManagedRuntime from "effect/ManagedRuntime"; |
| 11 | 15 | |
| 12 | −import { RuntimeSourceAuthMaterialLive } from "./auth/source-auth-material"; | |
| 13 | −import { RuntimeSourceCatalogStoreLive } from "./catalog/source/runtime"; | |
| 14 | −import { reconcileMissingSourceCatalogArtifacts } from "./catalog/source/reconcile"; | |
| 15 | −import { RuntimeSourceCatalogSyncLive } from "./catalog/source/sync"; | |
| 16 | +import { | |
| 17 | + RuntimeSourceAuthMaterialLive, | |
| 18 | +} from "./auth/source-auth-material"; | |
| 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 | 28 | import { |
| 17 | 29 | SourceTypeDeclarationsRefresherService, |
| 18 | 30 | type SourceTypeDeclarationsRefresherShape, |
| 19 | 31 | } from "./catalog/source/type-declarations"; |
| 20 | −import { createLiveExecutionManager, LiveExecutionManagerService } from "./execution/live"; | |
| 21 | −import { RuntimeExecutionResolverLive } from "./execution/workspace/environment"; | |
| 22 | −import type { CreateWorkspaceInternalToolMap, WorkspaceInternalToolContext } from "./execution/workspace/tool-invoker"; | |
| 23 | −import type { LoadedLocalExecutorConfig } from "./workspace-config"; | |
| 24 | −import type { LocalExecutorConfig } from "#schema"; | |
| 25 | −import type { InstanceConfig } from "../local/contracts"; | |
| 32 | +import { | |
| 33 | + createLiveExecutionManager, | |
| 34 | + LiveExecutionManagerService, | |
| 35 | +} from "./execution/live"; | |
| 36 | +import { | |
| 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 | 46 | import type { |
| 27 | − ExecutorWorkspaceContext, | |
| 28 | − ExecutorWorkspaceDescriptor, | |
| 29 | −} from "../workspace"; | |
| 47 | + LocalExecutorConfig, | |
| 48 | +} from "#schema"; | |
| 49 | +import type { | |
| 50 | + InstanceConfig, | |
| 51 | +} from "../local/contracts"; | |
| 52 | +import type { | |
| 53 | + ExecutorScopeContext, | |
| 54 | + ExecutorScopeDescriptor, | |
| 55 | +} from "../scope"; | |
| 30 | 56 | import { |
| 31 | 57 | LocalInstanceConfigService, |
| 32 | 58 | type DeleteSecretMaterial, |
| @@ -37,12 +63,14 @@ import { · 4 unmodified lines | ||
| 37 | 63 | SecretMaterialUpdaterService, |
| 38 | 64 | type StoreSecretMaterial, |
| 39 | 65 | type UpdateSecretMaterial, |
| 40 | −} from "./workspace/secret-material-providers"; | |
| 41 | −import type { LocalSourceArtifact } from "./source-artifacts"; | |
| 66 | +} from "./scope/secret-material-providers"; | |
| 67 | +import type { | |
| 68 | + LocalSourceArtifact, | |
| 69 | +} from "./source-artifacts"; | |
| 42 | 70 | import { |
| 43 | − type RuntimeLocalWorkspaceState, | |
| 44 | − RuntimeLocalWorkspaceLive, | |
| 45 | −} from "./workspace/runtime-context"; | |
| 71 | + type RuntimeLocalScopeState, | |
| 72 | + RuntimeLocalScopeLive, | |
| 73 | +} from "./scope/runtime-context"; | |
| 46 | 74 | import { |
| 47 | 75 | type LocalToolRuntime, |
| 48 | 76 | type LocalToolRuntimeLoaderShape, |
| @@ -53,14 +81,25 @@ import { · 4 unmodified lines | ||
| 53 | 81 | makeLocalStorageLayer, |
| 54 | 82 | type InstallationStoreShape, |
| 55 | 83 | type SourceArtifactStoreShape, |
| 56 | − type WorkspaceConfigStoreShape, | |
| 57 | − type WorkspaceStateStoreShape, | |
| 58 | −} from "./workspace/storage"; | |
| 59 | −import type { LocalWorkspaceState } from "./workspace-state"; | |
| 60 | −import { synchronizeLocalWorkspaceState } from "./workspace/workspace-sync"; | |
| 61 | −import { ExecutorStateStore, type ExecutorStateStoreShape } from "./executor-state-store"; | |
| 62 | −import { RuntimeSourceAuthServiceLive } from "./sources/source-auth-service"; | |
| 63 | −import { RuntimeSourceStoreLive } from "./sources/source-store"; | |
| 84 | + type ScopeConfigStoreShape, | |
| 85 | + type ScopeStateStoreShape, | |
| 86 | +} from "./scope/storage"; | |
| 87 | +import type { | |
| 88 | + LocalScopeState, | |
| 89 | +} from "./scope-state"; | |
| 90 | +import { | |
| 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 | 104 | export * from "./execution/state"; |
| 66 | 105 | export * from "./sources/executor-tools"; |
| @@ -73,28 +112,28 @@ export * from "./sources/source-credential-interactions"; · 6 unmodified lines | ||
| 73 | 112 | export * from "./sources/source-adapters/mcp"; |
| 74 | 113 | export * from "./sources/source-store"; |
| 75 | 114 | export * from "./executor-state-store"; |
| 76 | −export * from "./execution/workspace/environment"; | |
| 115 | +export * from "./execution/scope/environment"; | |
| 77 | 116 | export * from "../sources/inspection"; |
| 78 | 117 | export * from "../sources/discovery"; |
| 79 | 118 | export * from "./execution/service"; |
| 80 | 119 | export type { |
| 81 | − CreateWorkspaceInternalToolMap, | |
| 82 | − WorkspaceInternalToolContext, | |
| 83 | −} from "./execution/workspace/tool-invoker"; | |
| 120 | + CreateScopeInternalToolMap, | |
| 121 | + ScopeInternalToolContext, | |
| 122 | +} from "./execution/scope/tool-invoker"; | |
| 84 | 123 | export { |
| 85 | 124 | LocalInstanceConfigService, |
| 86 | 125 | SecretMaterialDeleterService, |
| 87 | 126 | SecretMaterialResolverService, |
| 88 | 127 | SecretMaterialStorerService, |
| 89 | 128 | SecretMaterialUpdaterService, |
| 90 | −} from "./workspace/secret-material-providers"; | |
| 129 | +} from "./scope/secret-material-providers"; | |
| 91 | 130 | export type { |
| 92 | 131 | DeleteSecretMaterial, |
| 93 | 132 | ResolveInstanceConfig, |
| 94 | 133 | ResolveSecretMaterial, |
| 95 | 134 | StoreSecretMaterial, |
| 96 | 135 | UpdateSecretMaterial, |
| 97 | −} from "./workspace/secret-material-providers"; | |
| 136 | +} from "./scope/secret-material-providers"; | |
| 98 | 137 | export { |
| 99 | 138 | builtInSourceAdapters, |
| 100 | 139 | connectableSourceAdapters, |
| @@ -112,7 +151,7 @@ export { · 11 unmodified lines | ||
| 112 | 151 | |
| 113 | 152 | export type ExecutorRuntimeOptions = { |
| 114 | 153 | executionResolver?: ResolveExecutionEnvironment; |
| 115 | − createInternalToolMap?: CreateWorkspaceInternalToolMap; | |
| 154 | + createInternalToolMap?: CreateScopeInternalToolMap; | |
| 116 | 155 | resolveSecretMaterial?: ResolveSecretMaterial; |
| 117 | 156 | getLocalServerBaseUrl?: () => string | undefined; |
| 118 | 157 | }; |
| @@ -134,18 +173,18 @@ export type BoundInstallationStore = { · 15 unmodified lines | ||
| 134 | 173 | getOrProvision: () => Effect.Effect<LocalInstallation, Error, never>; |
| 135 | 174 | }; |
| 136 | 175 | |
| 137 | −export type BoundWorkspaceConfigStore = { | |
| 176 | +export type BoundScopeConfigStore = { | |
| 138 | 177 | load: () => Effect.Effect<LoadedLocalExecutorConfig, Error, never>; |
| 139 | 178 | writeProject: ( |
| 140 | 179 | config: LocalExecutorConfig, |
| 141 | 180 | ) => Effect.Effect<void, Error, never>; |
| 142 | − resolveRelativePath: WorkspaceConfigStoreShape["resolveRelativePath"]; | |
| 181 | + resolveRelativePath: ScopeConfigStoreShape["resolveRelativePath"]; | |
| 143 | 182 | }; |
| 144 | 183 | |
| 145 | −export type BoundWorkspaceStateStore = { | |
| 146 | − load: () => Effect.Effect<LocalWorkspaceState, Error, never>; | |
| 184 | +export type BoundScopeStateStore = { | |
| 185 | + load: () => Effect.Effect<LocalScopeState, Error, never>; | |
| 147 | 186 | write: ( |
| 148 | − state: LocalWorkspaceState, | |
| 187 | + state: LocalScopeState, | |
| 149 | 188 | ) => Effect.Effect<void, Error, never>; |
| 150 | 189 | }; |
| 151 | 190 | |
| @@ -181,8 +220,8 @@ export type RuntimeInstanceConfigService = { · 29 unmodified lines | ||
| 181 | 220 | |
| 182 | 221 | export type RuntimeStorageServices = { |
| 183 | 222 | installation: BoundInstallationStore; |
| 184 | − workspaceConfig: BoundWorkspaceConfigStore; | |
| 185 | − workspaceState: BoundWorkspaceStateStore; | |
| 223 | + scopeConfig: BoundScopeConfigStore; | |
| 224 | + scopeState: BoundScopeStateStore; | |
| 186 | 225 | sourceArtifacts: BoundSourceArtifactStore; |
| 187 | 226 | executorState: ExecutorStateStoreShape; |
| 188 | 227 | secretMaterial: RuntimeSecretMaterialServices; |
| @@ -190,7 +229,7 @@ export type RuntimeStorageServices = { · 1 unmodified line | ||
| 190 | 229 | }; |
| 191 | 230 | |
| 192 | 231 | export type ExecutorRuntimeServices = { |
| 193 | − workspace: ExecutorWorkspaceDescriptor; | |
| 232 | + scope: ExecutorScopeDescriptor; | |
| 194 | 233 | storage: RuntimeStorageServices; |
| 195 | 234 | localToolRuntimeLoader?: BoundLocalToolRuntimeLoader; |
| 196 | 235 | sourceTypeDeclarationsRefresher?: BoundSourceTypeDeclarationsRefresher; |
| @@ -219,17 +258,17 @@ const toInstallationStoreShape = ( · 22 unmodified lines | ||
| 219 | 258 | getOrProvision: input.getOrProvision, |
| 220 | 259 | }); |
| 221 | 260 | |
| 222 | −const toWorkspaceConfigStoreShape = ( | |
| 223 | − input: BoundWorkspaceConfigStore, | |
| 224 | −): WorkspaceConfigStoreShape => ({ | |
| 261 | +const toScopeConfigStoreShape = ( | |
| 262 | + input: BoundScopeConfigStore, | |
| 263 | +): ScopeConfigStoreShape => ({ | |
| 225 | 264 | load: input.load, |
| 226 | 265 | writeProject: ({ config }) => input.writeProject(config), |
| 227 | 266 | resolveRelativePath: input.resolveRelativePath, |
| 228 | 267 | }); |
| 229 | 268 | |
| 230 | −const toWorkspaceStateStoreShape = ( | |
| 231 | − input: BoundWorkspaceStateStore, | |
| 232 | −): WorkspaceStateStoreShape => ({ | |
| 269 | +const toScopeStateStoreShape = ( | |
| 270 | + input: BoundScopeStateStore, | |
| 271 | +): ScopeStateStoreShape => ({ | |
| 233 | 272 | load: input.load, |
| 234 | 273 | write: ({ state }) => input.write(state), |
| 235 | 274 | }); |
| @@ -256,14 +295,14 @@ const makeInstanceConfigLayer = (input: RuntimeInstanceConfigService) => · 20 unmodified lines | ||
| 256 | 295 | |
| 257 | 296 | export const createExecutorRuntimeLayer = ( |
| 258 | 297 | input: ExecutorRuntimeOptions & ExecutorRuntimeServices & { |
| 259 | − localWorkspaceState: RuntimeLocalWorkspaceState; | |
| 298 | + localScopeState: RuntimeLocalScopeState; | |
| 260 | 299 | liveExecutionManager: ReturnType<typeof createLiveExecutionManager>; |
| 261 | 300 | }, |
| 262 | 301 | ) => { |
| 263 | 302 | const storageLayer = makeLocalStorageLayer({ |
| 264 | 303 | installationStore: toInstallationStoreShape(input.storage.installation), |
| 265 | − workspaceConfigStore: toWorkspaceConfigStoreShape(input.storage.workspaceConfig), | |
| 266 | − workspaceStateStore: toWorkspaceStateStoreShape(input.storage.workspaceState), | |
| 304 | + scopeConfigStore: toScopeConfigStoreShape(input.storage.scopeConfig), | |
| 305 | + scopeStateStore: toScopeStateStoreShape(input.storage.scopeState), | |
| 267 | 306 | sourceArtifactStore: toSourceArtifactStoreShape(input.storage.sourceArtifacts), |
| 268 | 307 | }); |
| 269 | 308 | const localToolRuntimeLayer = Layer.succeed( |
| @@ -283,7 +322,7 @@ export const createExecutorRuntimeLayer = ( · 13 unmodified lines | ||
| 283 | 322 | |
| 284 | 323 | const baseLayer = Layer.mergeAll( |
| 285 | 324 | Layer.succeed(ExecutorStateStore, input.storage.executorState), |
| 286 | − RuntimeLocalWorkspaceLive(input.localWorkspaceState), | |
| 325 | + RuntimeLocalScopeLive(input.localScopeState), | |
| 287 | 326 | storageLayer, |
| 288 | 327 | Layer.succeed(LiveExecutionManagerService, input.liveExecutionManager), |
| 289 | 328 | sourceTypeDeclarationsRefresherLayer, |
| @@ -381,16 +420,18 @@ export const createExecutorRuntimeFromServices = (input: { · 91 unmodified lines | ||
| 381 | 420 | .getOrProvision() |
| 382 | 421 | .pipe(Effect.mapError(toRuntimeBootstrapError)); |
| 383 | 422 | |
| 384 | − const loadedLocalConfig = yield* input.services.storage.workspaceConfig | |
| 423 | + const loadedLocalConfig = yield* input.services.storage.scopeConfig | |
| 385 | 424 | .load() |
| 386 | 425 | .pipe(Effect.mapError(toRuntimeBootstrapError)); |
| 387 | 426 | |
| 388 | − const runtimeWorkspace: ExecutorWorkspaceContext = { | |
| 389 | − ...input.services.workspace, | |
| 390 | − workspaceId: localInstallation.workspaceId, | |
| 391 | − accountId: localInstallation.accountId, | |
| 427 | + const runtimeWorkspace: ExecutorScopeContext = { | |
| 428 | + ...input.services.scope, | |
| 429 | + scopeId: localInstallation.scopeId, | |
| 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 | 435 | loadedConfig: loadedLocalConfig, |
| 395 | 436 | }) |
| 396 | 437 | .pipe( |
| @@ -399,11 +440,11 @@ export const createExecutorRuntimeFromServices = (input: { · 2 unmodified lines | ||
| 399 | 440 | installationStore: toInstallationStoreShape( |
| 400 | 441 | input.services.storage.installation, |
| 401 | 442 | ), |
| 402 | − workspaceConfigStore: toWorkspaceConfigStoreShape( | |
| 403 | − input.services.storage.workspaceConfig, | |
| 443 | + scopeConfigStore: toScopeConfigStoreShape( | |
| 444 | + input.services.storage.scopeConfig, | |
| 404 | 445 | ), |
| 405 | − workspaceStateStore: toWorkspaceStateStoreShape( | |
| 406 | − input.services.storage.workspaceState, | |
| 446 | + scopeStateStore: toScopeStateStoreShape( | |
| 447 | + input.services.storage.scopeState, | |
| 407 | 448 | ), |
| 408 | 449 | sourceArtifactStore: toSourceArtifactStoreShape( |
| 409 | 450 | input.services.storage.sourceArtifacts, |
| @@ -412,12 +453,9 @@ export const createExecutorRuntimeFromServices = (input: { · 2 unmodified lines | ||
| 412 | 453 | ), |
| 413 | 454 | ) |
| 414 | 455 | .pipe(Effect.mapError(toRuntimeBootstrapError)); |
| 415 | − const runtimeLocalWorkspaceState: RuntimeLocalWorkspaceState = { | |
| 416 | − workspace: runtimeWorkspace, | |
| 417 | − installation: { | |
| 418 | − workspaceId: localInstallation.workspaceId, | |
| 419 | − accountId: localInstallation.accountId, | |
| 420 | − }, | |
| 456 | + const runtimeLocalScopeState: RuntimeLocalScopeState = { | |
| 457 | + scope: runtimeWorkspace, | |
| 458 | + installation: localInstallation, | |
| 421 | 459 | loadedConfig: { |
| 422 | 460 | ...loadedLocalConfig, |
| 423 | 461 | config: effectiveLocalConfig, |
| @@ -428,14 +466,14 @@ export const createExecutorRuntimeFromServices = (input: { · 4 unmodified lines | ||
| 428 | 466 | const concreteRuntimeLayer = createExecutorRuntimeLayer({ |
| 429 | 467 | ...input, |
| 430 | 468 | ...input.services, |
| 431 | − localWorkspaceState: runtimeLocalWorkspaceState, | |
| 469 | + localScopeState: runtimeLocalScopeState, | |
| 432 | 470 | liveExecutionManager, |
| 433 | 471 | }); |
| 434 | 472 | const managedRuntime = ManagedRuntime.make(concreteRuntimeLayer); |
| 435 | 473 | yield* managedRuntime.runtimeEffect; |
| 436 | 474 | yield* reconcileMissingSourceCatalogArtifacts({ |
| 437 | − workspaceId: localInstallation.workspaceId, | |
| 438 | − actorAccountId: localInstallation.accountId, | |
| 475 | + scopeId: localInstallation.scopeId, | |
| 476 | + actorScopeId: localInstallation.actorScopeId, | |
| 439 | 477 | }).pipe( |
| 440 | 478 | Effect.provide(managedRuntime), |
| 441 | 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 | 10 | import { |
| 5 | 11 | PolicyIdSchema, |
| 6 | 12 | SourceIdSchema, |
| 7 | − WorkspaceIdSchema, | |
| 13 | + ScopeIdSchema, | |
| 8 | 14 | } from "#schema"; |
| 9 | 15 | |
| 10 | 16 | import { |
| @@ -12,7 +18,7 @@ import { · 1 unmodified line | ||
| 12 | 18 | type InvocationDescriptor, |
| 13 | 19 | } from "./invocation-policy-engine"; |
| 14 | 20 | |
| 15 | −const workspaceId = WorkspaceIdSchema.make("ws_policy_engine"); | |
| 21 | +const scopeId = ScopeIdSchema.make("ws_policy_engine"); | |
| 16 | 22 | const sourceId = SourceIdSchema.make("src_policy_engine"); |
| 17 | 23 | |
| 18 | 24 | const now = 1_700_000_000_000; |
| @@ -29,11 +35,11 @@ const baseDescriptor: InvocationDescriptor = { · 10 unmodified lines | ||
| 29 | 35 | }; |
| 30 | 36 | |
| 31 | 37 | const basePolicy = ( |
| 32 | − patch: Partial<LocalWorkspacePolicy> = {}, | |
| 33 | −): LocalWorkspacePolicy => ({ | |
| 38 | + patch: Partial<LocalScopePolicy> = {}, | |
| 39 | +): LocalScopePolicy => ({ | |
| 34 | 40 | id: PolicyIdSchema.make(`pol_${Math.random().toString(36).slice(2, 8)}`), |
| 35 | 41 | key: "vercel-dns", |
| 36 | − workspaceId, | |
| 42 | + scopeId, | |
| 37 | 43 | resourcePattern: "vercel.api.dns.createRecord", |
| 38 | 44 | effect: "allow", |
| 39 | 45 | approvalMode: "auto", |
| @@ -57,7 +63,7 @@ describe("invocation-policy-engine", () => { · 17 unmodified lines | ||
| 57 | 63 | args: {}, |
| 58 | 64 | policies: [], |
| 59 | 65 | context: { |
| 60 | − workspaceId, | |
| 66 | + scopeId, | |
| 61 | 67 | }, |
| 62 | 68 | }); |
| 63 | 69 | |
| @@ -70,7 +76,7 @@ describe("invocation-policy-engine", () => { · 6 unmodified lines | ||
| 70 | 76 | args: { domain: "testing.executor.sh" }, |
| 71 | 77 | policies: [], |
| 72 | 78 | context: { |
| 73 | − workspaceId, | |
| 79 | + scopeId, | |
| 74 | 80 | }, |
| 75 | 81 | }); |
| 76 | 82 | |
| @@ -85,7 +91,7 @@ describe("invocation-policy-engine", () => { · 8 unmodified lines | ||
| 85 | 91 | id: PolicyIdSchema.make("pol_allow"), |
| 86 | 92 | })], |
| 87 | 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 | 121 | context: { |
| 116 | − workspaceId, | |
| 122 | + scopeId, | |
| 117 | 123 | }, |
| 118 | 124 | }); |
| 119 | 125 | |
| @@ -130,7 +136,7 @@ describe("invocation-policy-engine", () => { · 10 unmodified lines | ||
| 130 | 136 | enabled: false, |
| 131 | 137 | })], |
| 132 | 138 | context: { |
| 133 | − workspaceId, | |
| 139 | + scopeId, | |
| 134 | 140 | }, |
| 135 | 141 | }); |
| 136 | 142 | |
| @@ -1,5 +1,5 @@ | ||
| 1 | 1 | import type { |
| 2 | − LocalWorkspacePolicy, | |
| 2 | + LocalScopePolicy, | |
| 3 | 3 | Source, |
| 4 | 4 | } from "#schema"; |
| 5 | 5 | |
| @@ -22,13 +22,13 @@ export type InvocationDescriptor = { · 16 unmodified lines | ||
| 22 | 22 | }; |
| 23 | 23 | |
| 24 | 24 | export type InvocationPolicyContext = { |
| 25 | − workspaceId: LocalWorkspacePolicy["workspaceId"]; | |
| 25 | + scopeId: LocalScopePolicy["scopeId"]; | |
| 26 | 26 | }; |
| 27 | 27 | |
| 28 | 28 | export type InvocationAuthorizationDecision = { |
| 29 | 29 | kind: "allow" | "deny" | "require_interaction"; |
| 30 | 30 | reason: string; |
| 31 | − matchedPolicyId: LocalWorkspacePolicy["id"] | null; | |
| 31 | + matchedPolicyId: LocalScopePolicy["id"] | null; | |
| 32 | 32 | }; |
| 33 | 33 | |
| 34 | 34 | const matchesGlob = (pattern: string, value: string): boolean => { |
| @@ -38,7 +38,7 @@ const matchesGlob = (pattern: string, value: string): boolean => { · 3 unmodified lines | ||
| 38 | 38 | return new RegExp(`^${escaped}$`).test(value); |
| 39 | 39 | }; |
| 40 | 40 | |
| 41 | −const policySpecificity = (policy: LocalWorkspacePolicy): number => | |
| 41 | +const policySpecificity = (policy: LocalScopePolicy): number => | |
| 42 | 42 | policy.priority + Math.max(1, policy.resourcePattern.replace(/\*/g, "").length); |
| 43 | 43 | |
| 44 | 44 | const defaultDecisionForInvocation = ( |
| @@ -60,7 +60,7 @@ const defaultDecisionForInvocation = ( · 15 unmodified lines | ||
| 60 | 60 | }; |
| 61 | 61 | |
| 62 | 62 | const resolvePolicyDecision = ( |
| 63 | − policy: LocalWorkspacePolicy, | |
| 63 | + policy: LocalScopePolicy, | |
| 64 | 64 | ): InvocationAuthorizationDecision => { |
| 65 | 65 | if (policy.effect === "deny") { |
| 66 | 66 | return { |
| @@ -88,13 +88,13 @@ const resolvePolicyDecision = ( · 21 unmodified lines | ||
| 88 | 88 | export const evaluateInvocationPolicy = (input: { |
| 89 | 89 | descriptor: InvocationDescriptor; |
| 90 | 90 | args: unknown; |
| 91 | − policies: ReadonlyArray<LocalWorkspacePolicy>; | |
| 91 | + policies: ReadonlyArray<LocalScopePolicy>; | |
| 92 | 92 | context: InvocationPolicyContext; |
| 93 | 93 | }): InvocationAuthorizationDecision => { |
| 94 | 94 | const matchingPolicies = input.policies |
| 95 | 95 | .filter((policy) => |
| 96 | 96 | policy.enabled |
| 97 | − && policy.workspaceId === input.context.workspaceId | |
| 97 | + && policy.scopeId === input.context.scopeId | |
| 98 | 98 | && matchesGlob(policy.resourcePattern, input.descriptor.toolPath)) |
| 99 | 99 | .sort((left, right) => |
| 100 | 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 | 5 | export type LoadedExecutorConfig = { |
| 4 | 6 | config: LocalExecutorConfig | null; |
| @@ -1,17 +1,17 @@ | ||
| 1 | 1 | import * as Data from "effect/Data"; |
| 2 | 2 | |
| 3 | −export class RuntimeLocalWorkspaceUnavailableError extends Data.TaggedError( | |
| 4 | − "RuntimeLocalWorkspaceUnavailableError", | |
| 3 | +export class RuntimeLocalScopeUnavailableError extends Data.TaggedError( | |
| 4 | + "RuntimeLocalScopeUnavailableError", | |
| 5 | 5 | )<{ |
| 6 | 6 | readonly message: string; |
| 7 | 7 | }> {} |
| 8 | 8 | |
| 9 | −export class RuntimeLocalWorkspaceMismatchError extends Data.TaggedError( | |
| 10 | − "RuntimeLocalWorkspaceMismatchError", | |
| 9 | +export class RuntimeLocalScopeMismatchError extends Data.TaggedError( | |
| 10 | + "RuntimeLocalScopeMismatchError", | |
| 11 | 11 | )<{ |
| 12 | 12 | readonly message: string; |
| 13 | − readonly requestedWorkspaceId: string; | |
| 14 | − readonly activeWorkspaceId: string; | |
| 13 | + readonly requestedScopeId: string; | |
| 14 | + readonly activeScopeId: string; | |
| 15 | 15 | }> {} |
| 16 | 16 | |
| 17 | 17 | export class LocalConfiguredSourceNotFoundError extends Data.TaggedError( |
| @@ -13,13 +13,13 @@ const LocalWorkspaceSourceStateSchema = Schema.Struct({ · 12 unmodified lines | ||
| 13 | 13 | updatedAt: TimestampMsSchema, |
| 14 | 14 | }); |
| 15 | 15 | |
| 16 | −const LocalWorkspacePolicyStateSchema = Schema.Struct({ | |
| 16 | +const LocalScopePolicyStateSchema = Schema.Struct({ | |
| 17 | 17 | id: PolicyIdSchema, |
| 18 | 18 | createdAt: TimestampMsSchema, |
| 19 | 19 | updatedAt: TimestampMsSchema, |
| 20 | 20 | }); |
| 21 | 21 | |
| 22 | −export const LocalWorkspaceStateSchema = Schema.Struct({ | |
| 22 | +export const LocalScopeStateSchema = Schema.Struct({ | |
| 23 | 23 | version: Schema.Literal(1), |
| 24 | 24 | sources: Schema.Record({ |
| 25 | 25 | key: Schema.String, |
| @@ -27,15 +27,15 @@ export const LocalWorkspaceStateSchema = Schema.Struct({ · 1 unmodified line | ||
| 27 | 27 | }), |
| 28 | 28 | policies: Schema.Record({ |
| 29 | 29 | key: Schema.String, |
| 30 | − value: LocalWorkspacePolicyStateSchema, | |
| 30 | + value: LocalScopePolicyStateSchema, | |
| 31 | 31 | }), |
| 32 | 32 | }); |
| 33 | 33 | |
| 34 | 34 | export type LocalWorkspaceSourceState = typeof LocalWorkspaceSourceStateSchema.Type; |
| 35 | −export type LocalWorkspacePolicyState = typeof LocalWorkspacePolicyStateSchema.Type; | |
| 36 | −export type LocalWorkspaceState = typeof LocalWorkspaceStateSchema.Type; | |
| 35 | +export type LocalScopePolicyState = typeof LocalScopePolicyStateSchema.Type; | |
| 36 | +export type LocalScopeState = typeof LocalScopeStateSchema.Type; | |
| 37 | 37 | |
| 38 | −export const defaultLocalWorkspaceState = (): LocalWorkspaceState => ({ | |
| 38 | +export const defaultLocalScopeState = (): LocalScopeState => ({ | |
| 39 | 39 | version: 1, |
| 40 | 40 | sources: {}, |
| 41 | 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 | 1 | import * as Effect from "effect/Effect"; |
| 2 | 2 | |
| 3 | −import { type LoadedLocalExecutorConfig } from "../workspace-config"; | |
| 4 | −import { WorkspaceStateStore } from "./storage"; | |
| 5 | −import { type LocalWorkspaceState } from "../workspace-state"; | |
| 3 | +import { | |
| 4 | + type LoadedLocalExecutorConfig, | |
| 5 | +} from "../scope-config"; | |
| 6 | +import { | |
| 7 | + ScopeStateStore, | |
| 8 | +} from "./storage"; | |
| 9 | +import { | |
| 10 | + type LocalScopeState, | |
| 11 | +} from "../scope-state"; | |
| 6 | 12 | |
| 7 | 13 | const trimOrNull = (value: string | null | undefined): string | null => { |
| 8 | 14 | if (value == null) { |
| @@ -35,10 +41,10 @@ export const derivePolicyConfigKey = ( · 26 unmodified lines | ||
| 35 | 41 | |
| 36 | 42 | const pruneLocalWorkspaceState = (input: { |
| 37 | 43 | loadedConfig: LoadedLocalExecutorConfig; |
| 38 | −}): Effect.Effect<LocalWorkspaceState, Error, WorkspaceStateStore> => | |
| 44 | +}): Effect.Effect<LocalScopeState, Error, ScopeStateStore> => | |
| 39 | 45 | Effect.gen(function* () { |
| 40 | − const workspaceStateStore = yield* WorkspaceStateStore; | |
| 41 | − const currentState = yield* workspaceStateStore.load(); | |
| 46 | + const scopeStateStore = yield* ScopeStateStore; | |
| 47 | + const currentState = yield* scopeStateStore.load(); | |
| 42 | 48 | |
| 43 | 49 | const configuredSourceIds = new Set( |
| 44 | 50 | Object.keys(input.loadedConfig.config?.sources ?? {}), |
| @@ -47,7 +53,7 @@ const pruneLocalWorkspaceState = (input: { · 2 unmodified lines | ||
| 47 | 53 | Object.keys(input.loadedConfig.config?.policies ?? {}), |
| 48 | 54 | ); |
| 49 | 55 | |
| 50 | − const nextState: LocalWorkspaceState = { | |
| 56 | + const nextState: LocalScopeState = { | |
| 51 | 57 | ...currentState, |
| 52 | 58 | sources: Object.fromEntries( |
| 53 | 59 | Object.entries(currentState.sources).filter(([sourceId]) => |
| @@ -65,16 +71,16 @@ const pruneLocalWorkspaceState = (input: { · 11 unmodified lines | ||
| 65 | 71 | return currentState; |
| 66 | 72 | } |
| 67 | 73 | |
| 68 | − yield* workspaceStateStore.write({ | |
| 74 | + yield* scopeStateStore.write({ | |
| 69 | 75 | state: nextState, |
| 70 | 76 | }); |
| 71 | 77 | |
| 72 | 78 | return nextState; |
| 73 | 79 | }); |
| 74 | 80 | |
| 75 | −export const synchronizeLocalWorkspaceState = (input: { | |
| 81 | +export const synchronizeLocalScopeState = (input: { | |
| 76 | 82 | loadedConfig: LoadedLocalExecutorConfig; |
| 77 | −}): Effect.Effect<LoadedLocalExecutorConfig["config"], Error, WorkspaceStateStore> => | |
| 83 | +}): Effect.Effect<LoadedLocalExecutorConfig["config"], Error, ScopeStateStore> => | |
| 78 | 84 | Effect.gen(function* () { |
| 79 | 85 | yield* pruneLocalWorkspaceState({ |
| 80 | 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 | 4 | import * as Context from "effect/Context"; |
| 3 | 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 | 5 | import * as Context from "effect/Context"; |
| 3 | 6 | import * as Layer from "effect/Layer"; |
| 4 | 7 | |
| 5 | −import type { LoadedLocalExecutorConfig } from "../workspace-config"; | |
| 6 | −import type { LocalSourceArtifact } from "../source-artifacts"; | |
| 7 | −import type { LocalWorkspaceState } from "../workspace-state"; | |
| 8 | −import type { SourceCatalogSyncResult } from "@executor/source-core"; | |
| 9 | −import type { Source } from "#schema"; | |
| 8 | +import type { | |
| 9 | + LoadedLocalExecutorConfig, | |
| 10 | +} from "../scope-config"; | |
| 11 | +import type { | |
| 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 | 24 | export type InstallationStoreShape = { |
| 12 | 25 | load: () => import("effect/Effect").Effect<LocalInstallation, Error, never>; |
| @@ -17,28 +30,28 @@ export class InstallationStore extends Context.Tag( · 4 unmodified lines | ||
| 17 | 30 | "#runtime/InstallationStore", |
| 18 | 31 | )<InstallationStore, InstallationStoreShape>() {} |
| 19 | 32 | |
| 20 | −export type WorkspaceConfigStoreShape = { | |
| 33 | +export type ScopeConfigStoreShape = { | |
| 21 | 34 | load: () => import("effect/Effect").Effect<LoadedLocalExecutorConfig, Error, never>; |
| 22 | 35 | writeProject: (input: { |
| 23 | 36 | config: LocalExecutorConfig; |
| 24 | 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( | |
| 29 | − "#runtime/WorkspaceConfigStore", | |
| 30 | −)<WorkspaceConfigStore, WorkspaceConfigStoreShape>() {} | |
| 41 | +export class ScopeConfigStore extends Context.Tag( | |
| 42 | + "#runtime/ScopeConfigStore", | |
| 43 | +)<ScopeConfigStore, ScopeConfigStoreShape>() {} | |
| 31 | 44 | |
| 32 | −export type WorkspaceStateStoreShape = { | |
| 33 | − load: () => import("effect/Effect").Effect<LocalWorkspaceState, Error, never>; | |
| 45 | +export type ScopeStateStoreShape = { | |
| 46 | + load: () => import("effect/Effect").Effect<LocalScopeState, Error, never>; | |
| 34 | 47 | write: (input: { |
| 35 | − state: LocalWorkspaceState; | |
| 48 | + state: LocalScopeState; | |
| 36 | 49 | }) => import("effect/Effect").Effect<void, Error, never>; |
| 37 | 50 | }; |
| 38 | 51 | |
| 39 | −export class WorkspaceStateStore extends Context.Tag( | |
| 40 | − "#runtime/WorkspaceStateStore", | |
| 41 | −)<WorkspaceStateStore, WorkspaceStateStoreShape>() {} | |
| 52 | +export class ScopeStateStore extends Context.Tag( | |
| 53 | + "#runtime/ScopeStateStore", | |
| 54 | +)<ScopeStateStore, ScopeStateStoreShape>() {} | |
| 42 | 55 | |
| 43 | 56 | export type SourceArtifactStoreShape = { |
| 44 | 57 | build: (input: { |
| @@ -63,33 +76,33 @@ export class SourceArtifactStore extends Context.Tag( · 18 unmodified lines | ||
| 63 | 76 | |
| 64 | 77 | export type LocalStorageServices = |
| 65 | 78 | | InstallationStore |
| 66 | − | WorkspaceConfigStore | |
| 67 | − | WorkspaceStateStore | |
| 79 | + | ScopeConfigStore | |
| 80 | + | ScopeStateStore | |
| 68 | 81 | | SourceArtifactStore; |
| 69 | 82 | |
| 70 | −export type WorkspaceStorageServices = | |
| 71 | − | WorkspaceConfigStore | |
| 72 | − | WorkspaceStateStore | |
| 83 | +export type ScopeStorageServices = | |
| 84 | + | ScopeConfigStore | |
| 85 | + | ScopeStateStore | |
| 73 | 86 | | SourceArtifactStore; |
| 74 | 87 | |
| 75 | −export const makeWorkspaceStorageLayer = (input: { | |
| 76 | − workspaceConfigStore: WorkspaceConfigStoreShape; | |
| 77 | − workspaceStateStore: WorkspaceStateStoreShape; | |
| 88 | +export const makeScopeStorageLayer = (input: { | |
| 89 | + scopeConfigStore: ScopeConfigStoreShape; | |
| 90 | + scopeStateStore: ScopeStateStoreShape; | |
| 78 | 91 | sourceArtifactStore: SourceArtifactStoreShape; |
| 79 | 92 | }) => |
| 80 | 93 | Layer.mergeAll( |
| 81 | − Layer.succeed(WorkspaceConfigStore, input.workspaceConfigStore), | |
| 82 | − Layer.succeed(WorkspaceStateStore, input.workspaceStateStore), | |
| 94 | + Layer.succeed(ScopeConfigStore, input.scopeConfigStore), | |
| 95 | + Layer.succeed(ScopeStateStore, input.scopeStateStore), | |
| 83 | 96 | Layer.succeed(SourceArtifactStore, input.sourceArtifactStore), |
| 84 | 97 | ); |
| 85 | 98 | |
| 86 | 99 | export const makeLocalStorageLayer = (input: { |
| 87 | 100 | installationStore: InstallationStoreShape; |
| 88 | − workspaceConfigStore: WorkspaceConfigStoreShape; | |
| 89 | − workspaceStateStore: WorkspaceStateStoreShape; | |
| 101 | + scopeConfigStore: ScopeConfigStoreShape; | |
| 102 | + scopeStateStore: ScopeStateStoreShape; | |
| 90 | 103 | sourceArtifactStore: SourceArtifactStoreShape; |
| 91 | 104 | }) => |
| 92 | 105 | Layer.mergeAll( |
| 93 | 106 | Layer.succeed(InstallationStore, input.installationStore), |
| 94 | − makeWorkspaceStorageLayer(input), | |
| 107 | + makeScopeStorageLayer(input), | |
| 95 | 108 | ); |
| @@ -9,7 +9,9 @@ import { · 8 unmodified lines | ||
| 9 | 9 | import * as Option from "effect/Option"; |
| 10 | 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 | 15 | import { |
| 14 | 16 | CatalogSnapshotV1Schema, |
| 15 | 17 | type CatalogSnapshotV1, |
| @@ -8,45 +8,50 @@ import { · 7 unmodified lines | ||
| 8 | 8 | type ToolPath, |
| 9 | 9 | } from "@executor/codemode-core"; |
| 10 | 10 | import { |
| 11 | − type AccountId, | |
| 11 | + type ScopeId, | |
| 12 | 12 | ExecutionIdSchema, |
| 13 | 13 | ExecutionInteractionIdSchema, |
| 14 | 14 | SourceSchema, |
| 15 | 15 | type Source, |
| 16 | − type WorkspaceId, | |
| 17 | 16 | } from "#schema"; |
| 18 | 17 | import * as Effect from "effect/Effect"; |
| 19 | 18 | import * as Cause from "effect/Cause"; |
| 20 | 19 | import * as Exit from "effect/Exit"; |
| 21 | 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 | 24 | import { |
| 24 | 25 | type LocalStorageServices, |
| 25 | 26 | type InstallationStoreShape, |
| 26 | 27 | type SourceArtifactStoreShape, |
| 27 | − type WorkspaceConfigStoreShape, | |
| 28 | − type WorkspaceStateStoreShape, | |
| 28 | + type ScopeConfigStoreShape, | |
| 29 | + type ScopeStateStoreShape, | |
| 29 | 30 | makeLocalStorageLayer, |
| 30 | −} from "../workspace/storage"; | |
| 31 | −import { provideOptionalRuntimeLocalWorkspace } from "../workspace/runtime-context"; | |
| 32 | −import { runtimeEffectError } from "../effect-errors"; | |
| 31 | +} from "../scope/storage"; | |
| 32 | +import { | |
| 33 | + provideOptionalRuntimeLocalScope, | |
| 34 | +} from "../scope/runtime-context"; | |
| 35 | +import { | |
| 36 | + runtimeEffectError, | |
| 37 | +} from "../effect-errors"; | |
| 33 | 38 | |
| 34 | 39 | /** Run an Effect as a Promise, preserving the original error (not FiberFailure). */ |
| 35 | 40 | const runEffect = async <A>( |
| 36 | 41 | effect: Effect.Effect<A, unknown, LocalStorageServices>, |
| 37 | 42 | storage: { |
| 38 | 43 | installationStore: InstallationStoreShape; |
| 39 | − workspaceConfigStore: WorkspaceConfigStoreShape; | |
| 40 | − workspaceStateStore: WorkspaceStateStoreShape; | |
| 44 | + scopeConfigStore: ScopeConfigStoreShape; | |
| 45 | + scopeStateStore: ScopeStateStoreShape; | |
| 41 | 46 | sourceArtifactStore: SourceArtifactStoreShape; |
| 42 | 47 | }, |
| 43 | − runtimeLocalWorkspace: RuntimeLocalWorkspaceState | null = null, | |
| 48 | + runtimeLocalScope: RuntimeLocalScopeState | null = null, | |
| 44 | 49 | ): Promise<A> => { |
| 45 | 50 | const baseLayer = makeLocalStorageLayer(storage); |
| 46 | 51 | const exit = await Effect.runPromiseExit( |
| 47 | − provideOptionalRuntimeLocalWorkspace( | |
| 52 | + provideOptionalRuntimeLocalScope( | |
| 48 | 53 | effect.pipe(Effect.provide(baseLayer)), |
| 49 | − runtimeLocalWorkspace, | |
| 54 | + runtimeLocalScope, | |
| 50 | 55 | ), |
| 51 | 56 | ); |
| 52 | 57 | if (Exit.isSuccess(exit)) return exit.value; |
| @@ -69,7 +74,9 @@ import { · 16 unmodified lines | ||
| 69 | 74 | executorAddableSourceAdapters, |
| 70 | 75 | sourceAdapterRequiresInteractiveConnect, |
| 71 | 76 | } from "./source-adapters"; |
| 72 | −import { decodeSourceCredentialSelectionContent } from "./source-credential-interactions"; | |
| 77 | +import { | |
| 78 | + decodeSourceCredentialSelectionContent, | |
| 79 | +} from "./source-credential-interactions"; | |
| 73 | 80 | |
| 74 | 81 | const ExecutorSourcesAddInputSchema = Schema.standardSchemaV1( |
| 75 | 82 | ExecutorAddSourceInputSchema, |
| @@ -112,7 +119,7 @@ export const EXECUTOR_SOURCES_ADD_HELP_LINES = [ · 36 unmodified lines | ||
| 112 | 119 | |
| 113 | 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 | 123 | ...EXECUTOR_SOURCES_ADD_HELP_LINES, |
| 117 | 124 | ].join("\n"); |
| 118 | 125 | |
| @@ -130,29 +137,29 @@ const toSerializableValue = <A>(value: A): A => · 11 unmodified lines | ||
| 130 | 137 | JSON.parse(JSON.stringify(value)) as A; |
| 131 | 138 | |
| 132 | 139 | type ExecutorSourcesAddToolArgs = |
| 133 | − | Omit<ExecutorMcpSourceInput, "workspaceId" | "actorAccountId" | "executionId" | "interactionId"> | |
| 140 | + | Omit<ExecutorMcpSourceInput, "scopeId" | "actorScopeId" | "executionId" | "interactionId"> | |
| 134 | 141 | | Omit< |
| 135 | 142 | ExecutorCredentialManagedSourceInput, |
| 136 | − "workspaceId" | "actorAccountId" | "executionId" | "interactionId" | |
| 143 | + "scopeId" | "actorScopeId" | "executionId" | "interactionId" | |
| 137 | 144 | >; |
| 138 | 145 | |
| 139 | 146 | type ExecutorGoogleDiscoveryToolArgs = Omit< |
| 140 | 147 | Extract<ExecutorCredentialManagedSourceInput, { service: string; version: string }>, |
| 141 | − "workspaceId" | "actorAccountId" | "executionId" | "interactionId" | |
| 148 | + "scopeId" | "actorScopeId" | "executionId" | "interactionId" | |
| 142 | 149 | >; |
| 143 | 150 | |
| 144 | 151 | type ExecutorOpenApiToolArgs = Omit< |
| 145 | 152 | Extract<ExecutorCredentialManagedSourceInput, { specUrl: string }>, |
| 146 | − "workspaceId" | "actorAccountId" | "executionId" | "interactionId" | |
| 153 | + "scopeId" | "actorScopeId" | "executionId" | "interactionId" | |
| 147 | 154 | >; |
| 148 | 155 | |
| 149 | 156 | type ExecutorGraphqlToolArgs = Omit< |
| 150 | 157 | Extract<ExecutorCredentialManagedSourceInput, { kind: "graphql" }>, |
| 151 | − "workspaceId" | "actorAccountId" | "executionId" | "interactionId" | |
| 158 | + "scopeId" | "actorScopeId" | "executionId" | "interactionId" | |
| 152 | 159 | >; |
| 153 | 160 | |
| 154 | 161 | type ExecutorCredentialPromptArgs = { |
| 155 | − workspaceId: WorkspaceId; | |
| 162 | + scopeId: ScopeId; | |
| 156 | 163 | sourceId: Source["id"]; |
| 157 | 164 | kind: ExecutorCredentialManagedSourceInput["kind"]; |
| 158 | 165 | endpoint?: string; |
| @@ -166,7 +173,7 @@ type ExecutorCredentialPromptArgs = { · 7 unmodified lines | ||
| 166 | 173 | |
| 167 | 174 | const isExecutorMcpToolArgs = ( |
| 168 | 175 | args: ExecutorSourcesAddToolArgs, |
| 169 | −): args is Omit<ExecutorMcpSourceInput, "workspaceId" | "actorAccountId" | "executionId" | "interactionId"> => | |
| 176 | +): args is Omit<ExecutorMcpSourceInput, "scopeId" | "actorScopeId" | "executionId" | "interactionId"> => | |
| 170 | 177 | args.kind === undefined || sourceAdapterRequiresInteractiveConnect(args.kind); |
| 171 | 178 | |
| 172 | 179 | const isExecutorCredentialManagedSourceInput = ( |
| @@ -176,8 +183,8 @@ const isExecutorCredentialManagedSourceInput = ( · 3 unmodified lines | ||
| 176 | 183 | |
| 177 | 184 | const prepareExecutorAddSourceInput = (input: { |
| 178 | 185 | args: ExecutorSourcesAddToolArgs; |
| 179 | − workspaceId: WorkspaceId; | |
| 180 | − accountId: AccountId; | |
| 186 | + scopeId: ScopeId; | |
| 187 | + actorScopeId: ScopeId; | |
| 181 | 188 | executionId: ReturnType<typeof toExecutionId>; |
| 182 | 189 | interactionId: ReturnType<typeof ExecutionInteractionIdSchema.make>; |
| 183 | 190 | }): ExecutorAddSourceInput => { |
| @@ -194,8 +201,8 @@ const prepareExecutorAddSourceInput = (input: { · 10 unmodified lines | ||
| 194 | 201 | args: input.args.args ?? null, |
| 195 | 202 | env: input.args.env ?? null, |
| 196 | 203 | cwd: input.args.cwd ?? null, |
| 197 | − workspaceId: input.workspaceId, | |
| 198 | − actorAccountId: input.accountId, | |
| 204 | + scopeId: input.scopeId, | |
| 205 | + actorScopeId: input.actorScopeId, | |
| 199 | 206 | executionId: input.executionId, |
| 200 | 207 | interactionId: input.interactionId, |
| 201 | 208 | } satisfies ExecutorMcpSourceInput; |
| @@ -205,8 +212,8 @@ const prepareExecutorAddSourceInput = (input: { · 3 unmodified lines | ||
| 205 | 212 | const args = input.args as ExecutorGoogleDiscoveryToolArgs; |
| 206 | 213 | return { |
| 207 | 214 | ...args, |
| 208 | − workspaceId: input.workspaceId, | |
| 209 | − actorAccountId: input.accountId, | |
| 215 | + scopeId: input.scopeId, | |
| 216 | + actorScopeId: input.actorScopeId, | |
| 210 | 217 | executionId: input.executionId, |
| 211 | 218 | interactionId: input.interactionId, |
| 212 | 219 | } satisfies Extract<ExecutorCredentialManagedSourceInput, { service: string; version: string }>; |
| @@ -216,8 +223,8 @@ const prepareExecutorAddSourceInput = (input: { · 3 unmodified lines | ||
| 216 | 223 | const args = input.args as ExecutorOpenApiToolArgs; |
| 217 | 224 | return { |
| 218 | 225 | ...args, |
| 219 | − workspaceId: input.workspaceId, | |
| 220 | − actorAccountId: input.accountId, | |
| 226 | + scopeId: input.scopeId, | |
| 227 | + actorScopeId: input.actorScopeId, | |
| 221 | 228 | executionId: input.executionId, |
| 222 | 229 | interactionId: input.interactionId, |
| 223 | 230 | } satisfies Extract<ExecutorCredentialManagedSourceInput, { specUrl: string }>; |
| @@ -226,8 +233,8 @@ const prepareExecutorAddSourceInput = (input: { · 2 unmodified lines | ||
| 226 | 233 | const args = input.args as ExecutorGraphqlToolArgs; |
| 227 | 234 | return { |
| 228 | 235 | ...args, |
| 229 | − workspaceId: input.workspaceId, | |
| 230 | − actorAccountId: input.accountId, | |
| 236 | + scopeId: input.scopeId, | |
| 237 | + actorScopeId: input.actorScopeId, | |
| 231 | 238 | executionId: input.executionId, |
| 232 | 239 | interactionId: input.interactionId, |
| 233 | 240 | } satisfies Extract<ExecutorCredentialManagedSourceInput, { kind: "graphql" }>; |
| @@ -235,13 +242,13 @@ const prepareExecutorAddSourceInput = (input: { · 1 unmodified line | ||
| 235 | 242 | |
| 236 | 243 | const resolveLocalCredentialUrl = (input: { |
| 237 | 244 | baseUrl: string; |
| 238 | − workspaceId: WorkspaceId; | |
| 245 | + scopeId: ScopeId; | |
| 239 | 246 | sourceId: Source["id"]; |
| 240 | 247 | executionId: string; |
| 241 | 248 | interactionId: string; |
| 242 | 249 | }): string => |
| 243 | 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 | 252 | input.baseUrl, |
| 246 | 253 | ).toString(); |
| 247 | 254 | |
| @@ -282,7 +289,7 @@ const promptForSourceCredentialSelection = (input: { · 34 unmodified lines | ||
| 282 | 289 | : `Open the secure credential page to connect ${input.source.name}`, |
| 283 | 290 | url: resolveLocalCredentialUrl({ |
| 284 | 291 | baseUrl: input.localServerBaseUrl, |
| 285 | − workspaceId: input.args.workspaceId, | |
| 292 | + scopeId: input.args.scopeId, | |
| 286 | 293 | sourceId: input.args.sourceId, |
| 287 | 294 | executionId: input.executionId, |
| 288 | 295 | interactionId: input.interactionId, |
| @@ -312,14 +319,14 @@ const promptForSourceCredentialSelection = (input: { · 23 unmodified lines | ||
| 312 | 319 | }); |
| 313 | 320 | |
| 314 | 321 | export const createExecutorToolMap = (input: { |
| 315 | − workspaceId: WorkspaceId; | |
| 316 | − accountId: AccountId; | |
| 322 | + scopeId: ScopeId; | |
| 323 | + actorScopeId: ScopeId; | |
| 317 | 324 | sourceAuthService: RuntimeSourceAuthService; |
| 318 | 325 | installationStore: InstallationStoreShape; |
| 319 | − workspaceConfigStore: WorkspaceConfigStoreShape; | |
| 320 | − workspaceStateStore: WorkspaceStateStoreShape; | |
| 326 | + scopeConfigStore: ScopeConfigStoreShape; | |
| 327 | + scopeStateStore: ScopeStateStoreShape; | |
| 321 | 328 | sourceArtifactStore: SourceArtifactStoreShape; |
| 322 | − runtimeLocalWorkspace: RuntimeLocalWorkspaceState | null; | |
| 329 | + runtimeLocalScope: RuntimeLocalScopeState | null; | |
| 323 | 330 | }): ToolMap => ({ |
| 324 | 331 | "executor.sources.add": toTool({ |
| 325 | 332 | tool: { |
| @@ -333,8 +340,8 @@ export const createExecutorToolMap = (input: { · 7 unmodified lines | ||
| 333 | 340 | ); |
| 334 | 341 | const preparedArgs = prepareExecutorAddSourceInput({ |
| 335 | 342 | args, |
| 336 | − workspaceId: input.workspaceId, | |
| 337 | − accountId: input.accountId, | |
| 343 | + scopeId: input.scopeId, | |
| 344 | + actorScopeId: input.actorScopeId, | |
| 338 | 345 | executionId, |
| 339 | 346 | interactionId, |
| 340 | 347 | }); |
| @@ -356,11 +363,11 @@ export const createExecutorToolMap = (input: { · 15 unmodified lines | ||
| 356 | 363 | ), |
| 357 | 364 | { |
| 358 | 365 | installationStore: input.installationStore, |
| 359 | − workspaceConfigStore: input.workspaceConfigStore, | |
| 360 | − workspaceStateStore: input.workspaceStateStore, | |
| 366 | + scopeConfigStore: input.scopeConfigStore, | |
| 367 | + scopeStateStore: input.scopeStateStore, | |
| 361 | 368 | sourceArtifactStore: input.sourceArtifactStore, |
| 362 | 369 | }, |
| 363 | − input.runtimeLocalWorkspace, | |
| 370 | + input.runtimeLocalScope, | |
| 364 | 371 | ); |
| 365 | 372 | |
| 366 | 373 | if (result.kind === "connected") { |
| @@ -379,7 +386,7 @@ export const createExecutorToolMap = (input: { · 12 unmodified lines | ||
| 379 | 386 | promptForSourceCredentialSelection({ |
| 380 | 387 | args: { |
| 381 | 388 | ...pendingArgs, |
| 382 | − workspaceId: input.workspaceId, | |
| 389 | + scopeId: input.scopeId, | |
| 383 | 390 | sourceId: pendingResult.source.id, |
| 384 | 391 | }, |
| 385 | 392 | credentialSlot: pendingResult.credentialSlot, |
| @@ -395,11 +402,11 @@ export const createExecutorToolMap = (input: { · 9 unmodified lines | ||
| 395 | 402 | }), |
| 396 | 403 | { |
| 397 | 404 | installationStore: input.installationStore, |
| 398 | − workspaceConfigStore: input.workspaceConfigStore, | |
| 399 | − workspaceStateStore: input.workspaceStateStore, | |
| 405 | + scopeConfigStore: input.scopeConfigStore, | |
| 406 | + scopeStateStore: input.scopeStateStore, | |
| 400 | 407 | sourceArtifactStore: input.sourceArtifactStore, |
| 401 | 408 | }, |
| 402 | − input.runtimeLocalWorkspace, | |
| 409 | + input.runtimeLocalScope, | |
| 403 | 410 | ); |
| 404 | 411 | |
| 405 | 412 | pendingArgs = pendingResult.credentialSlot === "import" |
| @@ -431,11 +438,11 @@ export const createExecutorToolMap = (input: { · 25 unmodified lines | ||
| 431 | 438 | ), |
| 432 | 439 | { |
| 433 | 440 | installationStore: input.installationStore, |
| 434 | − workspaceConfigStore: input.workspaceConfigStore, | |
| 435 | − workspaceStateStore: input.workspaceStateStore, | |
| 441 | + scopeConfigStore: input.scopeConfigStore, | |
| 442 | + scopeStateStore: input.scopeStateStore, | |
| 436 | 443 | sourceArtifactStore: input.sourceArtifactStore, |
| 437 | 444 | }, |
| 438 | − input.runtimeLocalWorkspace, | |
| 445 | + input.runtimeLocalScope, | |
| 439 | 446 | ); |
| 440 | 447 | |
| 441 | 448 | if (completed.kind === "connected") { |
| @@ -481,11 +488,11 @@ export const createExecutorToolMap = (input: { · 39 unmodified lines | ||
| 481 | 488 | }), |
| 482 | 489 | { |
| 483 | 490 | installationStore: input.installationStore, |
| 484 | − workspaceConfigStore: input.workspaceConfigStore, | |
| 485 | − workspaceStateStore: input.workspaceStateStore, | |
| 491 | + scopeConfigStore: input.scopeConfigStore, | |
| 492 | + scopeStateStore: input.scopeStateStore, | |
| 486 | 493 | sourceArtifactStore: input.sourceArtifactStore, |
| 487 | 494 | }, |
| 488 | − input.runtimeLocalWorkspace, | |
| 495 | + input.runtimeLocalScope, | |
| 489 | 496 | ); |
| 490 | 497 | |
| 491 | 498 | if (response.action !== "accept") { |
| @@ -494,17 +501,17 @@ export const createExecutorToolMap = (input: { · 2 unmodified lines | ||
| 494 | 501 | |
| 495 | 502 | const connected = await runEffect( |
| 496 | 503 | input.sourceAuthService.getSourceById({ |
| 497 | − workspaceId: input.workspaceId, | |
| 504 | + scopeId: input.scopeId, | |
| 498 | 505 | sourceId: result.source.id, |
| 499 | − actorAccountId: input.accountId, | |
| 506 | + actorScopeId: input.actorScopeId, | |
| 500 | 507 | }), |
| 501 | 508 | { |
| 502 | 509 | installationStore: input.installationStore, |
| 503 | − workspaceConfigStore: input.workspaceConfigStore, | |
| 504 | − workspaceStateStore: input.workspaceStateStore, | |
| 510 | + scopeConfigStore: input.scopeConfigStore, | |
| 511 | + scopeStateStore: input.scopeStateStore, | |
| 505 | 512 | sourceArtifactStore: input.sourceArtifactStore, |
| 506 | 513 | }, |
| 507 | − input.runtimeLocalWorkspace, | |
| 514 | + input.runtimeLocalScope, | |
| 508 | 515 | ); |
| 509 | 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 | 17 | type CapturedRequest = { |
| 8 | 18 | path: string; |
| @@ -1,5 +1,9 @@ | ||
| 1 | −import { createServer } from "node:http"; | |
| 2 | −import { fileURLToPath } from "node:url"; | |
| 1 | +import { | |
| 2 | + createServer, | |
| 3 | +} from "node:http"; | |
| 4 | +import { | |
| 5 | + fileURLToPath, | |
| 6 | +} from "node:url"; | |
| 3 | 7 | |
| 4 | 8 | import { |
| 5 | 9 | FileSystem, |
| @@ -9,7 +13,9 @@ import { · 3 unmodified lines | ||
| 9 | 13 | HttpApiSchema, |
| 10 | 14 | OpenApi, |
| 11 | 15 | } from "@effect/platform"; |
| 12 | −import { NodeFileSystem } from "@effect/platform-node"; | |
| 16 | +import { | |
| 17 | + NodeFileSystem, | |
| 18 | +} from "@effect/platform-node"; | |
| 13 | 19 | import { |
| 14 | 20 | buildOpenApiToolPresentation, |
| 15 | 21 | compileOpenApiToolDefinitions, |
| @@ -21,7 +27,11 @@ import { · 5 unmodified lines | ||
| 21 | 27 | compileGoogleDiscoveryToolDefinitions, |
| 22 | 28 | extractGoogleDiscoveryManifest, |
| 23 | 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 | 36 | import type { |
| 27 | 37 | Source, |
| @@ -32,13 +42,19 @@ import { · 4 unmodified lines | ||
| 32 | 42 | SourceCatalogIdSchema, |
| 33 | 43 | SourceCatalogRevisionIdSchema, |
| 34 | 44 | SourceIdSchema, |
| 35 | − WorkspaceIdSchema, | |
| 45 | + ScopeIdSchema, | |
| 36 | 46 | } from "#schema"; |
| 37 | 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"; | |
| 41 | −import type { CatalogSnapshotV1 } from "@executor/ir/model"; | |
| 52 | +import { | |
| 53 | + projectCatalogForAgentSdk, | |
| 54 | +} from "@executor/ir/catalog"; | |
| 55 | +import type { | |
| 56 | + CatalogSnapshotV1, | |
| 57 | +} from "@executor/ir/model"; | |
| 42 | 58 | import { |
| 43 | 59 | createCatalogTypeProjector, |
| 44 | 60 | projectedCatalogTypeRoots, |
| @@ -52,12 +68,20 @@ import { · 7 unmodified lines | ||
| 52 | 68 | expandCatalogToolByPath, |
| 53 | 69 | type LoadedSourceCatalog, |
| 54 | 70 | } from "../catalog/source/runtime"; |
| 55 | −import { invokeIrTool } from "../execution/ir-execution"; | |
| 56 | −import { createGoogleDiscoveryCatalogSnapshot } from "@executor/source-google-discovery"; | |
| 57 | −import { createGraphqlCatalogSnapshot } from "@executor/source-graphql"; | |
| 58 | −import { createOpenApiCatalogSnapshot } from "@executor/source-openapi"; | |
| 71 | +import { | |
| 72 | + invokeIrTool, | |
| 73 | +} from "../execution/ir-execution"; | |
| 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 | 86 | const readFixture = (name: string) => |
| 63 | 87 | FileSystem.FileSystem.pipe( |
| @@ -79,7 +103,7 @@ const makeSource = (input: { · 15 unmodified lines | ||
| 79 | 103 | binding: Source["binding"]; |
| 80 | 104 | }): Source => ({ |
| 81 | 105 | id: SourceIdSchema.make(input.id), |
| 82 | − workspaceId: FIXTURE_WORKSPACE_ID, | |
| 106 | + scopeId: FIXTURE_WORKSPACE_ID, | |
| 83 | 107 | name: input.name, |
| 84 | 108 | kind: input.kind, |
| 85 | 109 | endpoint: input.endpoint, |
| @@ -107,7 +131,7 @@ const makeLoadedCatalog = (input: { · 21 unmodified lines | ||
| 107 | 131 | ); |
| 108 | 132 | const sourceRecord = { |
| 109 | 133 | id: input.source.id, |
| 110 | − workspaceId: input.source.workspaceId, | |
| 134 | + scopeId: input.source.scopeId, | |
| 111 | 135 | catalogId, |
| 112 | 136 | catalogRevisionId: revisionId, |
| 113 | 137 | name: input.source.name, |
| @@ -725,8 +749,8 @@ describe("source adapter fixture matrix", () => { · 611 unmodified lines | ||
| 725 | 749 | |
| 726 | 750 | const getItemResult = await Effect.runPromise( |
| 727 | 751 | invokeIrTool({ |
| 728 | − workspaceId: source.workspaceId, | |
| 729 | − accountId: "acct_fixture" as any, | |
| 752 | + scopeId: source.scopeId, | |
| 753 | + actorScopeId: "acct_fixture" as any, | |
| 730 | 754 | tool: getItemTool, |
| 731 | 755 | auth, |
| 732 | 756 | args: { |
| @@ -741,8 +765,8 @@ describe("source adapter fixture matrix", () => { · 8 unmodified lines | ||
| 741 | 765 | ); |
| 742 | 766 | const submitFormResult = await Effect.runPromise( |
| 743 | 767 | invokeIrTool({ |
| 744 | − workspaceId: source.workspaceId, | |
| 745 | − accountId: "acct_fixture" as any, | |
| 768 | + scopeId: source.scopeId, | |
| 769 | + actorScopeId: "acct_fixture" as any, | |
| 746 | 770 | tool: submitFormTool, |
| 747 | 771 | auth, |
| 748 | 772 | args: { |
| @@ -898,8 +922,8 @@ describe("source adapter fixture matrix", () => { · 149 unmodified lines | ||
| 898 | 922 | |
| 899 | 923 | const result = await Effect.runPromise( |
| 900 | 924 | invokeIrTool({ |
| 901 | − workspaceId: source.workspaceId, | |
| 902 | − accountId: "acct_fixture" as any, | |
| 925 | + scopeId: source.scopeId, | |
| 926 | + actorScopeId: "acct_fixture" as any, | |
| 903 | 927 | tool, |
| 904 | 928 | auth, |
| 905 | 929 | args: { |
| @@ -1332,8 +1356,8 @@ describe("source adapter fixture matrix", () => { · 426 unmodified lines | ||
| 1332 | 1356 | } as const; |
| 1333 | 1357 | |
| 1334 | 1358 | const result = yield* invokeIrTool({ |
| 1335 | − workspaceId: source.workspaceId, | |
| 1336 | − accountId: "acct_fixture" as any, | |
| 1359 | + scopeId: source.scopeId, | |
| 1360 | + actorScopeId: "acct_fixture" as any, | |
| 1337 | 1361 | tool, |
| 1338 | 1362 | auth, |
| 1339 | 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"; | |
| 4 | −import { SourceIdSchema } from "#schema"; | |
| 5 | +import { | |
| 6 | + describe, | |
| 7 | + expect, | |
| 8 | + it, | |
| 9 | +} from "@effect/vitest"; | |
| 10 | +import { | |
| 11 | + SourceIdSchema, | |
| 12 | +} from "#schema"; | |
| 5 | 13 | |
| 6 | 14 | import * as Effect from "effect/Effect"; |
| 7 | 15 | |
| 8 | −import { googleDiscoverySourceAdapter } from "./google-discovery"; | |
| 9 | −import { snapshotFromSourceCatalogSyncResult } from "../catalog-sync-result"; | |
| 10 | −import { createSourceFromPayload } from "../source-definitions"; | |
| 11 | −import { runtimeEffectError } from "../../effect-errors"; | |
| 16 | +import { | |
| 17 | + googleDiscoverySourceAdapter, | |
| 18 | +} from "./google-discovery"; | |
| 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 | 29 | const fetchLiveDiscoveryDocument = async (): Promise<string> => { |
| 14 | 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 | 82 | await withStaticServer(discoveryDocument, async (discoveryUrl) => { |
| 67 | 83 | const source = await Effect.runPromise( |
| 68 | 84 | createSourceFromPayload({ |
| 69 | − workspaceId: "ws_test" as any, | |
| 85 | + scopeId: "ws_test" as any, | |
| 70 | 86 | sourceId: SourceIdSchema.make(`src_${crypto.randomUUID()}`), |
| 71 | 87 | payload: { |
| 72 | 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"; | |
| 4 | −import { SourceIdSchema } from "#schema"; | |
| 5 | +import { | |
| 6 | + describe, | |
| 7 | + expect, | |
| 8 | + it, | |
| 9 | +} from "@effect/vitest"; | |
| 10 | +import { | |
| 11 | + SourceIdSchema, | |
| 12 | +} from "#schema"; | |
| 5 | 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"; | |
| 9 | −import { graphqlSourceAdapter } from "./graphql"; | |
| 10 | −import { runtimeEffectError } from "../../effect-errors"; | |
| 18 | +import { | |
| 19 | + createSourceFromPayload, | |
| 20 | +} from "../source-definitions"; | |
| 21 | +import { | |
| 22 | + graphqlSourceAdapter, | |
| 23 | +} from "./graphql"; | |
| 24 | +import { | |
| 25 | + runtimeEffectError, | |
| 26 | +} from "../../effect-errors"; | |
| 11 | 27 | |
| 12 | 28 | const toError = (cause: unknown): Error => |
| 13 | 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 | 110 | const source = yield* createSourceFromPayload({ |
| 95 | − workspaceId: "ws_test" as any, | |
| 111 | + scopeId: "ws_test" as any, | |
| 96 | 112 | sourceId: SourceIdSchema.make(`src_${crypto.randomUUID()}`), |
| 97 | 113 | payload: { |
| 98 | 114 | name: "GraphQL Timeout", |
| @@ -4,9 +4,13 @@ import { · 3 unmodified lines | ||
| 4 | 4 | createSourceAdapterComposition, |
| 5 | 5 | type SourceAdapter, |
| 6 | 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 | 15 | export type * from "@executor/source-core"; |
| 12 | 16 | |
| @@ -10,7 +10,9 @@ import { · 9 unmodified lines | ||
| 10 | 10 | type Source, |
| 11 | 11 | type SourceAdapter, |
| 12 | 12 | } from "@executor/source-core"; |
| 13 | −import { runtimeEffectError } from "../../effect-errors"; | |
| 13 | +import { | |
| 14 | + runtimeEffectError, | |
| 15 | +} from "../../effect-errors"; | |
| 14 | 16 | |
| 15 | 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"; | |
| 4 | −import type { OAuthClientProvider } from "@modelcontextprotocol/sdk/client/auth.js"; | |
| 5 | −import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; | |
| 6 | −import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js"; | |
| 7 | −import { describe, expect, it } from "@effect/vitest"; | |
| 5 | +import { | |
| 6 | + createMcpExpressApp, | |
| 7 | +} from "@modelcontextprotocol/sdk/server/express.js"; | |
| 8 | +import type { | |
| 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 | 22 | import { |
| 9 | 23 | SourceCatalogIdSchema, |
| 10 | 24 | SourceCatalogRevisionIdSchema, |
| @@ -17,20 +31,39 @@ import type { · 6 unmodified lines | ||
| 17 | 31 | } from "#schema"; |
| 18 | 32 | |
| 19 | 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"; | |
| 23 | −import type { CatalogSnapshotV1 } from "@executor/ir/model"; | |
| 24 | −import { createCatalogTypeProjector, projectedCatalogTypeRoots } from "../../catalog/catalog-typescript"; | |
| 25 | −import { invokeIrTool } from "../../execution/ir-execution"; | |
| 38 | +import { | |
| 39 | + projectCatalogForAgentSdk, | |
| 40 | +} from "@executor/ir/catalog"; | |
| 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 | 51 | import { |
| 27 | 52 | expandCatalogToolByPath, |
| 28 | 53 | type LoadedSourceCatalog, |
| 29 | 54 | } from "../../catalog/source/runtime"; |
| 30 | −import { snapshotFromSourceCatalogSyncResult } from "../catalog-sync-result"; | |
| 31 | −import { createSourceFromPayload } from "../source-definitions"; | |
| 32 | −import { mcpSourceAdapter } from "./mcp"; | |
| 33 | −import { runtimeEffectError } from "../../effect-errors"; | |
| 55 | +import { | |
| 56 | + snapshotFromSourceCatalogSyncResult, | |
| 57 | +} from "../catalog-sync-result"; | |
| 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 | 68 | type RealMcpServer = { |
| 36 | 69 | endpoint: string; |
| @@ -47,7 +80,7 @@ const makeLoadedCatalog = (input: { · 10 unmodified lines | ||
| 47 | 80 | ); |
| 48 | 81 | const sourceRecord = { |
| 49 | 82 | id: input.source.id, |
| 50 | − workspaceId: input.source.workspaceId, | |
| 83 | + scopeId: input.source.scopeId, | |
| 51 | 84 | catalogId, |
| 52 | 85 | catalogRevisionId: revisionId, |
| 53 | 86 | name: input.source.name, |
| @@ -535,9 +568,15 @@ const makeStatefulMcpServer = Effect.acquireRelease( · 481 unmodified lines | ||
| 535 | 568 | ); |
| 536 | 569 | |
| 537 | 570 | const STDIO_TEST_SERVER_SCRIPT = ` |
| 538 | −import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; | |
| 539 | −import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; | |
| 540 | −import { z } from "zod/v4"; | |
| 571 | +import { | |
| 572 | + McpServer, | |
| 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 | 581 | const server = new McpServer( |
| 543 | 582 | { name: "mcp-stdio-test-server", version: "1.0.0" }, |
| @@ -594,7 +633,7 @@ describe("mcp source adapter", () => { · 50 unmodified lines | ||
| 594 | 633 | Effect.gen(function* () { |
| 595 | 634 | const realServer = yield* makeRealMcpServer; |
| 596 | 635 | const source = yield* createSourceFromPayload({ |
| 597 | − workspaceId: "ws_test" as any, | |
| 636 | + scopeId: "ws_test" as any, | |
| 598 | 637 | sourceId: SourceIdSchema.make(`src_${randomUUID()}`), |
| 599 | 638 | payload: { |
| 600 | 639 | name: "MCP Demo", |
| @@ -682,7 +721,7 @@ describe("mcp source adapter", () => { · 81 unmodified lines | ||
| 682 | 721 | Effect.gen(function* () { |
| 683 | 722 | const realServer = yield* makeRealMcpServer; |
| 684 | 723 | const source = yield* createSourceFromPayload({ |
| 685 | − workspaceId: "ws_test" as any, | |
| 724 | + scopeId: "ws_test" as any, | |
| 686 | 725 | sourceId: SourceIdSchema.make(`src_${randomUUID()}`), |
| 687 | 726 | payload: { |
| 688 | 727 | name: "MCP Demo", |
| @@ -733,8 +772,8 @@ describe("mcp source adapter", () => { · 44 unmodified lines | ||
| 733 | 772 | } |
| 734 | 773 | |
| 735 | 774 | const result = yield* invokeIrTool({ |
| 736 | − workspaceId: source.workspaceId, | |
| 737 | − accountId: "acct_test" as any, | |
| 775 | + scopeId: source.scopeId, | |
| 776 | + actorScopeId: "acct_test" as any, | |
| 738 | 777 | tool, |
| 739 | 778 | auth: { |
| 740 | 779 | placements: [], |
| @@ -769,7 +808,7 @@ describe("mcp source adapter", () => { · 28 unmodified lines | ||
| 769 | 808 | const realServer = yield* makeAuthenticatedMcpServer("Bearer mcp-auth-token"); |
| 770 | 809 | const authProvider = makeStaticAuthProvider("mcp-auth-token"); |
| 771 | 810 | const source = yield* createSourceFromPayload({ |
| 772 | − workspaceId: "ws_test" as any, | |
| 811 | + scopeId: "ws_test" as any, | |
| 773 | 812 | sourceId: SourceIdSchema.make(`src_${randomUUID()}`), |
| 774 | 813 | payload: { |
| 775 | 814 | name: "Authenticated MCP Demo", |
| @@ -822,8 +861,8 @@ describe("mcp source adapter", () => { · 46 unmodified lines | ||
| 822 | 861 | } |
| 823 | 862 | |
| 824 | 863 | const result = yield* invokeIrTool({ |
| 825 | − workspaceId: source.workspaceId, | |
| 826 | − accountId: "acct_test" as any, | |
| 864 | + scopeId: source.scopeId, | |
| 865 | + actorScopeId: "acct_test" as any, | |
| 827 | 866 | tool, |
| 828 | 867 | auth: resolvedAuth, |
| 829 | 868 | args: { |
| @@ -849,7 +888,7 @@ describe("mcp source adapter", () => { · 19 unmodified lines | ||
| 849 | 888 | Effect.gen(function* () { |
| 850 | 889 | const realServer = yield* makeStatefulMcpServer; |
| 851 | 890 | const source = yield* createSourceFromPayload({ |
| 852 | − workspaceId: "ws_test" as any, | |
| 891 | + scopeId: "ws_test" as any, | |
| 853 | 892 | sourceId: SourceIdSchema.make(`src_${randomUUID()}`), |
| 854 | 893 | payload: { |
| 855 | 894 | name: "Stateful MCP Demo", |
| @@ -905,8 +944,8 @@ describe("mcp source adapter", () => { · 49 unmodified lines | ||
| 905 | 944 | } |
| 906 | 945 | |
| 907 | 946 | const incrementResult = yield* invokeIrTool({ |
| 908 | − workspaceId: source.workspaceId, | |
| 909 | − accountId: "acct_test" as any, | |
| 947 | + scopeId: source.scopeId, | |
| 948 | + actorScopeId: "acct_test" as any, | |
| 910 | 949 | tool: incrementTool, |
| 911 | 950 | auth: { |
| 912 | 951 | placements: [], |
| @@ -924,8 +963,8 @@ describe("mcp source adapter", () => { · 11 unmodified lines | ||
| 924 | 963 | }); |
| 925 | 964 | |
| 926 | 965 | const readResult = yield* invokeIrTool({ |
| 927 | − workspaceId: source.workspaceId, | |
| 928 | − accountId: "acct_test" as any, | |
| 966 | + scopeId: source.scopeId, | |
| 967 | + actorScopeId: "acct_test" as any, | |
| 929 | 968 | tool: readTool, |
| 930 | 969 | auth: { |
| 931 | 970 | placements: [], |
| @@ -970,7 +1009,7 @@ describe("mcp source adapter", () => { · 38 unmodified lines | ||
| 970 | 1009 | it.scoped("supports stdio MCP sources", () => |
| 971 | 1010 | Effect.gen(function* () { |
| 972 | 1011 | const source = yield* createSourceFromPayload({ |
| 973 | − workspaceId: "ws_test" as any, | |
| 1012 | + scopeId: "ws_test" as any, | |
| 974 | 1013 | sourceId: SourceIdSchema.make(`src_${randomUUID()}`), |
| 975 | 1014 | payload: { |
| 976 | 1015 | name: "Stdio MCP Demo", |
| @@ -1025,8 +1064,8 @@ describe("mcp source adapter", () => { · 48 unmodified lines | ||
| 1025 | 1064 | } |
| 1026 | 1065 | |
| 1027 | 1066 | const result = yield* invokeIrTool({ |
| 1028 | − workspaceId: source.workspaceId, | |
| 1029 | − accountId: "acct_test" as any, | |
| 1067 | + scopeId: source.scopeId, | |
| 1068 | + actorScopeId: "acct_test" as any, | |
| 1030 | 1069 | tool, |
| 1031 | 1070 | auth: { |
| 1032 | 1071 | placements: [], |
| @@ -9,7 +9,6 @@ import { · 8 unmodified lines | ||
| 9 | 9 | type SourceAdapterOauth2SetupConfig, |
| 10 | 10 | } from "@executor/source-core"; |
| 11 | 11 | import { |
| 12 | − AccountId, | |
| 13 | 12 | type CredentialSlot, |
| 14 | 13 | McpSourceAuthSessionDataJsonSchema, |
| 15 | 14 | type McpSourceAuthSessionData, |
| @@ -30,12 +29,12 @@ import { · 14 unmodified lines | ||
| 30 | 29 | SourceSchema, |
| 31 | 30 | type SecretRef, |
| 32 | 31 | type StringMap, |
| 33 | − WorkspaceOauthClientIdSchema, | |
| 34 | − WorkspaceSourceOauthClientIdSchema, | |
| 35 | − WorkspaceSourceOauthClientMetadataJsonSchema, | |
| 36 | − type WorkspaceOauthClient, | |
| 37 | − type WorkspaceSourceOauthClientRedirectMode, | |
| 38 | − type WorkspaceId, | |
| 32 | + ScopeOauthClientIdSchema, | |
| 33 | + ScopedSourceOauthClientIdSchema, | |
| 34 | + ScopedSourceOauthClientMetadataJsonSchema, | |
| 35 | + type ScopeOauthClient, | |
| 36 | + type ScopedSourceOauthClientRedirectMode, | |
| 37 | + type ScopeId, | |
| 39 | 38 | } from "#schema"; |
| 40 | 39 | import * as Context from "effect/Context"; |
| 41 | 40 | import * as Either from "effect/Either"; |
| @@ -51,15 +50,17 @@ import { · 9 unmodified lines | ||
| 51 | 50 | type LiveExecutionManager, |
| 52 | 51 | } from "../execution/live"; |
| 53 | 52 | import { |
| 54 | − getRuntimeLocalWorkspaceOption, | |
| 55 | − provideOptionalRuntimeLocalWorkspace, | |
| 56 | − type RuntimeLocalWorkspaceState, | |
| 57 | −} from "../workspace/runtime-context"; | |
| 53 | + getRuntimeLocalScopeOption, | |
| 54 | + provideOptionalRuntimeLocalScope, | |
| 55 | + type RuntimeLocalScopeState, | |
| 56 | +} from "../scope/runtime-context"; | |
| 58 | 57 | import { |
| 59 | 58 | exchangeMcpOAuthAuthorizationCode, |
| 60 | 59 | startMcpOAuthAuthorization, |
| 61 | 60 | } from "../auth/mcp-oauth"; |
| 62 | −import { createPersistedMcpOAuthSourceAuth } from "../auth/mcp-auth-provider"; | |
| 61 | +import { | |
| 62 | + createPersistedMcpOAuthSourceAuth, | |
| 63 | +} from "../auth/mcp-auth-provider"; | |
| 63 | 64 | import { |
| 64 | 65 | createSourceFromPayload, |
| 65 | 66 | updateSourceFromPayload, |
| @@ -79,7 +80,7 @@ import { · 13 unmodified lines | ||
| 79 | 80 | SecretMaterialResolverService, |
| 80 | 81 | SecretMaterialStorerService, |
| 81 | 82 | type StoreSecretMaterial, |
| 82 | −} from "../workspace/secret-material-providers"; | |
| 83 | +} from "../scope/secret-material-providers"; | |
| 83 | 84 | import { |
| 84 | 85 | removeAuthLeaseAndSecrets, |
| 85 | 86 | upsertOauth2AuthorizedUserLeaseFromTokenResponse, |
| @@ -97,14 +98,23 @@ import { · 11 unmodified lines | ||
| 97 | 98 | createPkceCodeVerifier, |
| 98 | 99 | exchangeOAuth2AuthorizationCode, |
| 99 | 100 | } from "../auth/oauth2-pkce"; |
| 100 | −import { startOauthLoopbackRedirectServer } from "../auth/oauth-loopback"; | |
| 101 | +import { | |
| 102 | + startOauthLoopbackRedirectServer, | |
| 103 | +} from "../auth/oauth-loopback"; | |
| 101 | 104 | import { |
| 102 | 105 | type RuntimeSourceStore, |
| 103 | 106 | RuntimeSourceStoreService, |
| 104 | 107 | } from "./source-store"; |
| 105 | −import type { WorkspaceStorageServices } from "../workspace/storage"; | |
| 106 | −import { ExecutorStateStore, type ExecutorStateStoreShape } from "../executor-state-store"; | |
| 107 | −import { runtimeEffectError } from "../effect-errors"; | |
| 108 | +import type { | |
| 109 | + ScopeStorageServices, | |
| 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 | 119 | const trimOrNull = (value: string | null | undefined): string | null => { |
| 110 | 120 | if (value === null || value === undefined) { |
| @@ -199,11 +209,11 @@ const normalizeMcpEndpoint = (input: { · 88 unmodified lines | ||
| 199 | 209 | |
| 200 | 210 | const resolveSourceCredentialOauthCompleteUrl = (input: { |
| 201 | 211 | baseUrl: string; |
| 202 | − workspaceId: WorkspaceId; | |
| 212 | + scopeId: ScopeId; | |
| 203 | 213 | sourceId: Source["id"]; |
| 204 | 214 | }): string => |
| 205 | 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 | 217 | input.baseUrl, |
| 208 | 218 | ).toString(); |
| 209 | 219 | |
| @@ -217,10 +227,10 @@ const resolveSourceOAuthCallbackUrl = (input: { · 7 unmodified lines | ||
| 217 | 227 | |
| 218 | 228 | const resolveWorkspaceProviderOauthCompleteUrl = (input: { |
| 219 | 229 | baseUrl: string; |
| 220 | − workspaceId: WorkspaceId; | |
| 230 | + scopeId: ScopeId; | |
| 221 | 231 | }): string => |
| 222 | 232 | new URL( |
| 223 | − `/v1/workspaces/${encodeURIComponent(input.workspaceId)}/oauth/provider/callback`, | |
| 233 | + `/v1/workspaces/${encodeURIComponent(input.scopeId)}/oauth/provider/callback`, | |
| 224 | 234 | input.baseUrl, |
| 225 | 235 | ).toString(); |
| 226 | 236 | |
| @@ -491,7 +501,7 @@ const serializeJson = (value: unknown): string | null => { · 264 unmodified lines | ||
| 491 | 501 | }; |
| 492 | 502 | |
| 493 | 503 | const updateSourceStatus = Effect.fn("source.status.update")((sourceStore: RuntimeSourceStore, source: Source, input: { |
| 494 | − actorAccountId?: AccountId | null; | |
| 504 | + actorScopeId?: ScopeId | null; | |
| 495 | 505 | status: Source["status"]; |
| 496 | 506 | lastError?: string | null; |
| 497 | 507 | auth?: Source["auth"]; |
| @@ -499,9 +509,9 @@ const updateSourceStatus = Effect.fn("source.status.update")((sourceStore: Runti · 1 unmodified line | ||
| 499 | 509 | }) => |
| 500 | 510 | Effect.gen(function* () { |
| 501 | 511 | const latest = yield* sourceStore.loadSourceById({ |
| 502 | − workspaceId: source.workspaceId, | |
| 512 | + scopeId: source.scopeId, | |
| 503 | 513 | sourceId: source.id, |
| 504 | − actorAccountId: input.actorAccountId, | |
| 514 | + actorScopeId: input.actorScopeId, | |
| 505 | 515 | }); |
| 506 | 516 | |
| 507 | 517 | return yield* sourceStore.persistSource({ |
| @@ -512,7 +522,7 @@ const updateSourceStatus = Effect.fn("source.status.update")((sourceStore: Runti · 4 unmodified lines | ||
| 512 | 522 | importAuth: input.importAuth ?? latest.importAuth, |
| 513 | 523 | updatedAt: Date.now(), |
| 514 | 524 | }, { |
| 515 | − actorAccountId: input.actorAccountId, | |
| 525 | + actorScopeId: input.actorScopeId, | |
| 516 | 526 | }); |
| 517 | 527 | }).pipe( |
| 518 | 528 | Effect.withSpan("source.status.update", { |
| @@ -564,8 +574,8 @@ export type ExecutorHttpSourceAuthInput = · 45 unmodified lines | ||
| 564 | 574 | export type ExecutorAddSourceInput = |
| 565 | 575 | | { |
| 566 | 576 | kind?: "mcp"; |
| 567 | − workspaceId: WorkspaceId; | |
| 568 | − actorAccountId?: AccountId | null; | |
| 577 | + scopeId: ScopeId; | |
| 578 | + actorScopeId?: ScopeId | null; | |
| 569 | 579 | executionId: SourceAuthSession["executionId"]; |
| 570 | 580 | interactionId: SourceAuthSession["interactionId"]; |
| 571 | 581 | endpoint?: string | null; |
| @@ -581,8 +591,8 @@ export type ExecutorAddSourceInput = · 9 unmodified lines | ||
| 581 | 591 | } |
| 582 | 592 | | { |
| 583 | 593 | kind: "openapi"; |
| 584 | − workspaceId: WorkspaceId; | |
| 585 | − actorAccountId?: AccountId | null; | |
| 594 | + scopeId: ScopeId; | |
| 595 | + actorScopeId?: ScopeId | null; | |
| 586 | 596 | executionId: SourceAuthSession["executionId"]; |
| 587 | 597 | interactionId: SourceAuthSession["interactionId"]; |
| 588 | 598 | endpoint: string; |
| @@ -595,8 +605,8 @@ export type ExecutorAddSourceInput = · 6 unmodified lines | ||
| 595 | 605 | } |
| 596 | 606 | | { |
| 597 | 607 | kind: "graphql"; |
| 598 | − workspaceId: WorkspaceId; | |
| 599 | − actorAccountId?: AccountId | null; | |
| 608 | + scopeId: ScopeId; | |
| 609 | + actorScopeId?: ScopeId | null; | |
| 600 | 610 | executionId: SourceAuthSession["executionId"]; |
| 601 | 611 | interactionId: SourceAuthSession["interactionId"]; |
| 602 | 612 | endpoint: string; |
| @@ -608,15 +618,15 @@ export type ExecutorAddSourceInput = · 5 unmodified lines | ||
| 608 | 618 | } |
| 609 | 619 | | { |
| 610 | 620 | kind: "google_discovery"; |
| 611 | − workspaceId: WorkspaceId; | |
| 612 | − actorAccountId?: AccountId | null; | |
| 621 | + scopeId: ScopeId; | |
| 622 | + actorScopeId?: ScopeId | null; | |
| 613 | 623 | executionId: SourceAuthSession["executionId"]; |
| 614 | 624 | interactionId: SourceAuthSession["interactionId"]; |
| 615 | 625 | service: string; |
| 616 | 626 | version: string; |
| 617 | 627 | discoveryUrl?: string | null; |
| 618 | 628 | scopes?: ReadonlyArray<string> | null; |
| 619 | − workspaceOauthClientId?: WorkspaceOauthClient["id"] | null; | |
| 629 | + scopeOauthClientId?: ScopeOauthClient["id"] | null; | |
| 620 | 630 | oauthClient?: SourceOauthClientInput | null; |
| 621 | 631 | name?: string | null; |
| 622 | 632 | namespace?: string | null; |
| @@ -641,8 +651,8 @@ export type ExecutorMcpSourceInput = Exclude< · 18 unmodified lines | ||
| 641 | 651 | >; |
| 642 | 652 | |
| 643 | 653 | export type ConnectMcpSourceInput = { |
| 644 | − workspaceId: WorkspaceId; | |
| 645 | − actorAccountId?: AccountId | null; | |
| 654 | + scopeId: ScopeId; | |
| 655 | + actorScopeId?: ScopeId | null; | |
| 646 | 656 | sourceId?: Source["id"] | null; |
| 647 | 657 | endpoint?: string | null; |
| 648 | 658 | name?: string | null; |
| @@ -659,11 +669,11 @@ export type ConnectMcpSourceInput = { · 10 unmodified lines | ||
| 659 | 669 | }; |
| 660 | 670 | |
| 661 | 671 | export type ConnectGoogleDiscoveryBatchInput = { |
| 662 | − workspaceId: WorkspaceId; | |
| 663 | − actorAccountId?: AccountId | null; | |
| 672 | + scopeId: ScopeId; | |
| 673 | + actorScopeId?: ScopeId | null; | |
| 664 | 674 | executionId: SourceAuthSession["executionId"]; |
| 665 | 675 | interactionId: SourceAuthSession["interactionId"]; |
| 666 | − workspaceOauthClientId: WorkspaceOauthClient["id"]; | |
| 676 | + scopeOauthClientId: ScopeOauthClient["id"]; | |
| 667 | 677 | sources: ReadonlyArray<{ |
| 668 | 678 | service: string; |
| 669 | 679 | version: string; |
| @@ -687,8 +697,8 @@ export type ConnectGoogleDiscoveryBatchResult = { · 17 unmodified lines | ||
| 687 | 697 | } | null; |
| 688 | 698 | }; |
| 689 | 699 | |
| 690 | −export type CreateWorkspaceOauthClientInput = { | |
| 691 | − workspaceId: WorkspaceId; | |
| 700 | +export type CreateScopeOauthClientInput = { | |
| 701 | + scopeId: ScopeId; | |
| 692 | 702 | providerKey: string; |
| 693 | 703 | label?: string | null; |
| 694 | 704 | oauthClient: SourceOauthClientInput; |
| @@ -707,8 +717,8 @@ export type SourceOAuthProviderInput = { · 12 unmodified lines | ||
| 707 | 717 | }; |
| 708 | 718 | |
| 709 | 719 | export type StartSourceOAuthSessionInput = { |
| 710 | − workspaceId: WorkspaceId; | |
| 711 | − actorAccountId?: AccountId | null; | |
| 720 | + scopeId: ScopeId; | |
| 721 | + actorScopeId?: ScopeId | null; | |
| 712 | 722 | provider: SourceOAuthProviderInput; |
| 713 | 723 | baseUrl?: string | null; |
| 714 | 724 | displayName?: string | null; |
| @@ -928,11 +938,11 @@ type ResolvedSourceOauthClient = { · 213 unmodified lines | ||
| 928 | 938 | providerKey: string; |
| 929 | 939 | clientId: string; |
| 930 | 940 | clientSecret: SecretRef | null; |
| 931 | − redirectMode: WorkspaceSourceOauthClientRedirectMode; | |
| 941 | + redirectMode: ScopedSourceOauthClientRedirectMode; | |
| 932 | 942 | }; |
| 933 | 943 | |
| 934 | −type ResolvedWorkspaceOauthClient = ResolvedSourceOauthClient & { | |
| 935 | − id: WorkspaceOauthClient["id"]; | |
| 944 | +type ResolvedScopeOauthClient = ResolvedSourceOauthClient & { | |
| 945 | + id: ScopeOauthClient["id"]; | |
| 936 | 946 | label: string | null; |
| 937 | 947 | }; |
| 938 | 948 | |
| @@ -954,22 +964,22 @@ type RuntimeProviderAuthResult = · 15 unmodified lines | ||
| 954 | 964 | authorizationUrl: string; |
| 955 | 965 | }; |
| 956 | 966 | |
| 957 | −const decodeWorkspaceSourceOauthClientMetadataOption = Schema.decodeUnknownOption( | |
| 958 | − WorkspaceSourceOauthClientMetadataJsonSchema, | |
| 967 | +const decodeScopedSourceOauthClientMetadataOption = Schema.decodeUnknownOption( | |
| 968 | + ScopedSourceOauthClientMetadataJsonSchema, | |
| 959 | 969 | ); |
| 960 | 970 | |
| 961 | −const encodeWorkspaceSourceOauthClientMetadataJson = Schema.encodeSync( | |
| 962 | − WorkspaceSourceOauthClientMetadataJsonSchema, | |
| 971 | +const encodeScopedSourceOauthClientMetadataJson = Schema.encodeSync( | |
| 972 | + ScopedSourceOauthClientMetadataJsonSchema, | |
| 963 | 973 | ); |
| 964 | 974 | |
| 965 | 975 | const sourceOauthClientRedirectMode = (client: { |
| 966 | 976 | clientMetadataJson: string | null; |
| 967 | −}): WorkspaceSourceOauthClientRedirectMode => { | |
| 977 | +}): ScopedSourceOauthClientRedirectMode => { | |
| 968 | 978 | if (client.clientMetadataJson === null) { |
| 969 | 979 | return "app_callback"; |
| 970 | 980 | } |
| 971 | 981 | |
| 972 | − const decoded = decodeWorkspaceSourceOauthClientMetadataOption( | |
| 982 | + const decoded = decodeScopedSourceOauthClientMetadataOption( | |
| 973 | 983 | client.clientMetadataJson, |
| 974 | 984 | ); |
| 975 | 985 | if (Option.isNone(decoded)) { |
| @@ -1009,8 +1019,8 @@ const upsertSourceOauthClient = (input: { · 33 unmodified lines | ||
| 1009 | 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({ | |
| 1013 | − workspaceId: input.source.workspaceId, | |
| 1022 | + const existing = yield* input.executorState.sourceOauthClients.getByScopeSourceAndProvider({ | |
| 1023 | + scopeId: input.source.scopeId, | |
| 1014 | 1024 | sourceId: input.source.id, |
| 1015 | 1025 | providerKey: setupConfig.providerKey, |
| 1016 | 1026 | }); |
| @@ -1029,18 +1039,18 @@ const upsertSourceOauthClient = (input: { · 12 unmodified lines | ||
| 1029 | 1039 | const now = Date.now(); |
| 1030 | 1040 | const clientId = Option.isSome(existing) |
| 1031 | 1041 | ? existing.value.id |
| 1032 | − : WorkspaceSourceOauthClientIdSchema.make( | |
| 1042 | + : ScopedSourceOauthClientIdSchema.make( | |
| 1033 | 1043 | `src_oauth_client_${crypto.randomUUID()}`, |
| 1034 | 1044 | ); |
| 1035 | 1045 | yield* input.executorState.sourceOauthClients.upsert({ |
| 1036 | 1046 | id: clientId, |
| 1037 | − workspaceId: input.source.workspaceId, | |
| 1047 | + scopeId: input.source.scopeId, | |
| 1038 | 1048 | sourceId: input.source.id, |
| 1039 | 1049 | providerKey: setupConfig.providerKey, |
| 1040 | 1050 | clientId: normalizedOauthClient.clientId, |
| 1041 | 1051 | clientSecretProviderId: clientSecretRef?.providerId ?? null, |
| 1042 | 1052 | clientSecretHandle: clientSecretRef?.handle ?? null, |
| 1043 | − clientMetadataJson: encodeWorkspaceSourceOauthClientMetadataJson({ | |
| 1053 | + clientMetadataJson: encodeScopedSourceOauthClientMetadataJson({ | |
| 1044 | 1054 | redirectMode: normalizedOauthClient.redirectMode ?? "app_callback", |
| 1045 | 1055 | }), |
| 1046 | 1056 | createdAt: Option.isSome(existing) ? existing.value.createdAt : now, |
| @@ -1084,8 +1094,8 @@ const resolveExistingSourceOauthClient = (input: { · 37 unmodified lines | ||
| 1084 | 1094 | return null; |
| 1085 | 1095 | } |
| 1086 | 1096 | |
| 1087 | − const existing = yield* input.executorState.sourceOauthClients.getByWorkspaceSourceAndProvider({ | |
| 1088 | − workspaceId: input.source.workspaceId, | |
| 1097 | + const existing = yield* input.executorState.sourceOauthClients.getByScopeSourceAndProvider({ | |
| 1098 | + scopeId: input.source.scopeId, | |
| 1089 | 1099 | sourceId: input.source.id, |
| 1090 | 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 | 1115 | executorState: ExecutorStateStoreShape; |
| 1106 | − workspaceId: WorkspaceId; | |
| 1116 | + scopeId: ScopeId; | |
| 1107 | 1117 | providerKey: string; |
| 1108 | 1118 | oauthClient: SourceOauthClientInput; |
| 1109 | 1119 | label?: string | null; |
| @@ -1111,7 +1121,7 @@ const createWorkspaceOauthClient = (input: { · 1 unmodified line | ||
| 1111 | 1121 | input: SourceOauthClientInput, |
| 1112 | 1122 | ) => Effect.Effect<SourceOauthClientInput, Error, never>; |
| 1113 | 1123 | storeSecretMaterial: StoreSecretMaterial; |
| 1114 | −}): Effect.Effect<ResolvedWorkspaceOauthClient, Error, never> => | |
| 1124 | +}): Effect.Effect<ResolvedScopeOauthClient, Error, never> => | |
| 1115 | 1125 | Effect.gen(function* () { |
| 1116 | 1126 | const normalizedOauthClient = input.normalizeOauthClient |
| 1117 | 1127 | ? yield* input.normalizeOauthClient(input.oauthClient) |
| @@ -1123,19 +1133,19 @@ const createWorkspaceOauthClient = (input: { · 5 unmodified lines | ||
| 1123 | 1133 | }) |
| 1124 | 1134 | : null; |
| 1125 | 1135 | const now = Date.now(); |
| 1126 | − const id = WorkspaceOauthClientIdSchema.make( | |
| 1136 | + const id = ScopeOauthClientIdSchema.make( | |
| 1127 | 1137 | `ws_oauth_client_${crypto.randomUUID()}`, |
| 1128 | 1138 | ); |
| 1129 | 1139 | |
| 1130 | − yield* input.executorState.workspaceOauthClients.upsert({ | |
| 1140 | + yield* input.executorState.scopeOauthClients.upsert({ | |
| 1131 | 1141 | id, |
| 1132 | − workspaceId: input.workspaceId, | |
| 1142 | + scopeId: input.scopeId, | |
| 1133 | 1143 | providerKey: input.providerKey, |
| 1134 | 1144 | label: trimOrNull(input.label) ?? null, |
| 1135 | 1145 | clientId: normalizedOauthClient.clientId, |
| 1136 | 1146 | clientSecretProviderId: clientSecretRef?.providerId ?? null, |
| 1137 | 1147 | clientSecretHandle: clientSecretRef?.handle ?? null, |
| 1138 | − clientMetadataJson: encodeWorkspaceSourceOauthClientMetadataJson({ | |
| 1148 | + clientMetadataJson: encodeScopedSourceOauthClientMetadataJson({ | |
| 1139 | 1149 | redirectMode: normalizedOauthClient.redirectMode ?? "app_callback", |
| 1140 | 1150 | }), |
| 1141 | 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 | 1166 | executorState: ExecutorStateStoreShape; |
| 1157 | − workspaceId: WorkspaceId; | |
| 1158 | − oauthClientId: WorkspaceOauthClient["id"]; | |
| 1167 | + scopeId: ScopeId; | |
| 1168 | + oauthClientId: ScopeOauthClient["id"]; | |
| 1159 | 1169 | providerKey: string; |
| 1160 | −}): Effect.Effect<ResolvedWorkspaceOauthClient | null, Error, never> => | |
| 1170 | + localScopeState?: RuntimeLocalScopeState; | |
| 1171 | +}): Effect.Effect<ResolvedScopeOauthClient | null, Error, never> => | |
| 1161 | 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 | 1174 | if (Option.isNone(existing)) { |
| 1164 | 1175 | return null; |
| 1165 | 1176 | } |
| 1166 | 1177 | |
| 1178 | + const allowedScopeIds = resolvedScopeSearchOrder({ | |
| 1179 | + scopeId: input.scopeId, | |
| 1180 | + localScopeState: input.localScopeState, | |
| 1181 | + }); | |
| 1167 | 1182 | if ( |
| 1168 | − existing.value.workspaceId !== input.workspaceId | |
| 1183 | + !allowedScopeIds.includes(existing.value.scopeId) | |
| 1169 | 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 | 1189 | return { |
| @@ -1192,6 +1207,25 @@ const providerGrantCoversScopes = ( · 17 unmodified lines | ||
| 1192 | 1207 | const normalizeScopes = (scopes: ReadonlyArray<string>): ReadonlyArray<string> => |
| 1193 | 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 | 1229 | const authorizationParamsMatch = ( |
| 1196 | 1230 | left: SourceAdapterOauth2SetupConfig["authorizationParams"], |
| 1197 | 1231 | right: SourceAdapterOauth2SetupConfig["authorizationParams"], |
| @@ -1272,34 +1306,44 @@ const mergeRuntimeProviderAuthSetupConfig = ( · 74 unmodified lines | ||
| 1272 | 1306 | |
| 1273 | 1307 | const findReusableProviderGrant = (input: { |
| 1274 | 1308 | executorState: ExecutorStateStoreShape; |
| 1275 | − workspaceId: WorkspaceId; | |
| 1276 | − actorAccountId?: AccountId | null; | |
| 1309 | + scopeId: ScopeId; | |
| 1310 | + actorScopeId?: ScopeId | null; | |
| 1277 | 1311 | providerKey: string; |
| 1278 | − oauthClientId: WorkspaceOauthClient["id"]; | |
| 1312 | + oauthClientId: ScopeOauthClient["id"]; | |
| 1279 | 1313 | requiredScopes: ReadonlyArray<string>; |
| 1314 | + localScopeState?: RuntimeLocalScopeState; | |
| 1280 | 1315 | }): Effect.Effect<import("effect/Option").Option<import("#schema").ProviderAuthGrant>, Error, never> => |
| 1281 | − Effect.map( | |
| 1282 | − input.executorState.providerAuthGrants.listByWorkspaceActorAndProvider({ | |
| 1283 | − workspaceId: input.workspaceId, | |
| 1284 | − actorAccountId: input.actorAccountId ?? null, | |
| 1285 | − providerKey: input.providerKey, | |
| 1286 | − }), | |
| 1287 | − (grants) => | |
| 1288 | − Option.fromNullable( | |
| 1289 | − grants.find( | |
| 1290 | − (grant) => | |
| 1291 | − grant.oauthClientId === input.oauthClientId | |
| 1292 | − && providerGrantCoversScopes(grant.grantedScopes, input.requiredScopes), | |
| 1293 | − ), | |
| 1294 | − ), | |
| 1295 | − ); | |
| 1316 | + Effect.gen(function* () { | |
| 1317 | + const scopeIds = resolvedScopeSearchOrder({ | |
| 1318 | + scopeId: input.scopeId, | |
| 1319 | + localScopeState: input.localScopeState, | |
| 1320 | + }); | |
| 1321 | + | |
| 1322 | + for (const candidateScopeId of scopeIds) { | |
| 1323 | + const grants = yield* input.executorState.providerAuthGrants.listByScopeActorAndProvider({ | |
| 1324 | + scopeId: candidateScopeId, | |
| 1325 | + actorScopeId: input.actorScopeId ?? null, | |
| 1326 | + providerKey: input.providerKey, | |
| 1327 | + }); | |
| 1328 | + const matchingGrant = grants.find( | |
| 1329 | + (grant) => | |
| 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 | 1341 | const upsertProviderAuthGrant = (input: { |
| 1298 | 1342 | executorState: ExecutorStateStoreShape; |
| 1299 | − workspaceId: WorkspaceId; | |
| 1300 | − actorAccountId?: AccountId | null; | |
| 1343 | + scopeId: ScopeId; | |
| 1344 | + actorScopeId?: ScopeId | null; | |
| 1301 | 1345 | providerKey: string; |
| 1302 | − oauthClientId: WorkspaceOauthClient["id"]; | |
| 1346 | + oauthClientId: ScopeOauthClient["id"]; | |
| 1303 | 1347 | tokenEndpoint: string; |
| 1304 | 1348 | clientAuthentication: "none" | "client_secret_post"; |
| 1305 | 1349 | headerName: string; |
| @@ -1328,8 +1372,8 @@ const upsertProviderAuthGrant = (input: { · 22 unmodified lines | ||
| 1328 | 1372 | const now = Date.now(); |
| 1329 | 1373 | const nextGrant = { |
| 1330 | 1374 | id: existingGrant?.id ?? ProviderAuthGrantIdSchema.make(`provider_grant_${crypto.randomUUID()}`), |
| 1331 | − workspaceId: input.workspaceId, | |
| 1332 | − actorAccountId: input.actorAccountId ?? null, | |
| 1375 | + scopeId: input.scopeId, | |
| 1376 | + actorScopeId: input.actorScopeId ?? null, | |
| 1333 | 1377 | providerKey: input.providerKey, |
| 1334 | 1378 | oauthClientId: input.oauthClientId, |
| 1335 | 1379 | tokenEndpoint: input.tokenEndpoint, |
| @@ -1369,16 +1413,16 @@ const startOauth2PkceSourceCredentialSetup = (input: { · 33 unmodified lines | ||
| 1369 | 1413 | executorState: ExecutorStateStoreShape; |
| 1370 | 1414 | sourceStore: RuntimeSourceStore; |
| 1371 | 1415 | source: Source; |
| 1372 | − actorAccountId?: AccountId | null; | |
| 1416 | + actorScopeId?: ScopeId | null; | |
| 1373 | 1417 | executionId?: SourceAuthSession["executionId"]; |
| 1374 | 1418 | interactionId?: SourceAuthSession["interactionId"]; |
| 1375 | 1419 | baseUrl: string; |
| 1376 | − redirectModeOverride?: WorkspaceSourceOauthClientRedirectMode; | |
| 1420 | + redirectModeOverride?: ScopedSourceOauthClientRedirectMode; | |
| 1377 | 1421 | storeSecretMaterial: StoreSecretMaterial; |
| 1378 | 1422 | }): Effect.Effect< |
| 1379 | 1423 | Extract<ExecutorSourceAddResult, { kind: "oauth_required" }> | null, |
| 1380 | 1424 | Error, |
| 1381 | − WorkspaceStorageServices | |
| 1425 | + ScopeStorageServices | |
| 1382 | 1426 | > => |
| 1383 | 1427 | Effect.gen(function* () { |
| 1384 | 1428 | const adapter = getSourceAdapterForSource(input.source); |
| @@ -1404,7 +1448,7 @@ const startOauth2PkceSourceCredentialSetup = (input: { · 19 unmodified lines | ||
| 1404 | 1448 | const state = crypto.randomUUID(); |
| 1405 | 1449 | const completionUrl = resolveSourceCredentialOauthCompleteUrl({ |
| 1406 | 1450 | baseUrl: input.baseUrl, |
| 1407 | − workspaceId: input.source.workspaceId, | |
| 1451 | + scopeId: input.source.scopeId, | |
| 1408 | 1452 | sourceId: input.source.id, |
| 1409 | 1453 | }); |
| 1410 | 1454 | const redirectMode = input.redirectModeOverride ?? oauthClient.redirectMode; |
| @@ -1429,9 +1473,9 @@ const startOauth2PkceSourceCredentialSetup = (input: { · 18 unmodified lines | ||
| 1429 | 1473 | |
| 1430 | 1474 | yield* input.executorState.sourceAuthSessions.upsert({ |
| 1431 | 1475 | id: sessionId, |
| 1432 | − workspaceId: input.source.workspaceId, | |
| 1476 | + scopeId: input.source.scopeId, | |
| 1433 | 1477 | sourceId: input.source.id, |
| 1434 | − actorAccountId: input.actorAccountId ?? null, | |
| 1478 | + actorScopeId: input.actorScopeId ?? null, | |
| 1435 | 1479 | credentialSlot: "runtime", |
| 1436 | 1480 | executionId: input.executionId ?? null, |
| 1437 | 1481 | interactionId: input.interactionId ?? null, |
| @@ -1463,7 +1507,7 @@ const startOauth2PkceSourceCredentialSetup = (input: { · 25 unmodified lines | ||
| 1463 | 1507 | }); |
| 1464 | 1508 | |
| 1465 | 1509 | const authRequiredSource = yield* updateSourceStatus(input.sourceStore, input.source, { |
| 1466 | − actorAccountId: input.actorAccountId, | |
| 1510 | + actorScopeId: input.actorScopeId, | |
| 1467 | 1511 | status: "auth_required", |
| 1468 | 1512 | lastError: null, |
| 1469 | 1513 | }); |
| @@ -1486,13 +1530,13 @@ const startOauth2PkceSourceCredentialSetup = (input: { · 16 unmodified lines | ||
| 1486 | 1530 | const startProviderOauthBatchCredentialSetup = (input: { |
| 1487 | 1531 | executorState: ExecutorStateStoreShape; |
| 1488 | 1532 | sourceStore: RuntimeSourceStore; |
| 1489 | − workspaceId: WorkspaceId; | |
| 1490 | − actorAccountId?: AccountId | null; | |
| 1533 | + scopeId: ScopeId; | |
| 1534 | + actorScopeId?: ScopeId | null; | |
| 1491 | 1535 | executionId?: SourceAuthSession["executionId"]; |
| 1492 | 1536 | interactionId?: SourceAuthSession["interactionId"]; |
| 1493 | 1537 | baseUrl: string; |
| 1494 | − redirectModeOverride?: WorkspaceSourceOauthClientRedirectMode; | |
| 1495 | − workspaceOauthClient: ResolvedWorkspaceOauthClient; | |
| 1538 | + redirectModeOverride?: ScopedSourceOauthClientRedirectMode; | |
| 1539 | + scopeOauthClient: ResolvedScopeOauthClient; | |
| 1496 | 1540 | setupConfig: SourceAdapterOauth2SetupConfig; |
| 1497 | 1541 | targetSources: ReadonlyArray<{ |
| 1498 | 1542 | source: Source; |
| @@ -1502,7 +1546,7 @@ const startProviderOauthBatchCredentialSetup = (input: { · 3 unmodified lines | ||
| 1502 | 1546 | sessionId: SourceAuthSession["id"]; |
| 1503 | 1547 | authorizationUrl: string; |
| 1504 | 1548 | source: Source; |
| 1505 | −}, Error, WorkspaceStorageServices> => | |
| 1549 | +}, Error, ScopeStorageServices> => | |
| 1506 | 1550 | Effect.gen(function* () { |
| 1507 | 1551 | if (input.targetSources.length === 0) { |
| 1508 | 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 | 1556 | const state = crypto.randomUUID(); |
| 1513 | 1557 | const completionUrl = resolveWorkspaceProviderOauthCompleteUrl({ |
| 1514 | 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 | 1562 | const redirectServer = redirectMode === "loopback" |
| 1519 | 1563 | ? yield* startOauthLoopbackRedirectServer({ |
| 1520 | 1564 | completionUrl, |
| @@ -1526,7 +1570,7 @@ const startProviderOauthBatchCredentialSetup = (input: { · 5 unmodified lines | ||
| 1526 | 1570 | return yield* Effect.gen(function* () { |
| 1527 | 1571 | const authorizationUrl = buildOAuth2AuthorizationUrl({ |
| 1528 | 1572 | authorizationEndpoint: input.setupConfig.authorizationEndpoint, |
| 1529 | − clientId: input.workspaceOauthClient.clientId, | |
| 1573 | + clientId: input.scopeOauthClient.clientId, | |
| 1530 | 1574 | redirectUri, |
| 1531 | 1575 | scopes: [...normalizeScopes(input.setupConfig.scopes)], |
| 1532 | 1576 | state, |
| @@ -1537,9 +1581,9 @@ const startProviderOauthBatchCredentialSetup = (input: { · 4 unmodified lines | ||
| 1537 | 1581 | |
| 1538 | 1582 | yield* input.executorState.sourceAuthSessions.upsert({ |
| 1539 | 1583 | id: sessionId, |
| 1540 | − workspaceId: input.workspaceId, | |
| 1584 | + scopeId: input.scopeId, | |
| 1541 | 1585 | sourceId: SourceIdSchema.make(`oauth_provider_${crypto.randomUUID()}`), |
| 1542 | − actorAccountId: input.actorAccountId ?? null, | |
| 1586 | + actorScopeId: input.actorScopeId ?? null, | |
| 1543 | 1587 | credentialSlot: "runtime", |
| 1544 | 1588 | executionId: input.executionId ?? null, |
| 1545 | 1589 | interactionId: input.interactionId ?? null, |
| @@ -1552,7 +1596,7 @@ const startProviderOauthBatchCredentialSetup = (input: { · 6 unmodified lines | ||
| 1552 | 1596 | authorizationEndpoint: input.setupConfig.authorizationEndpoint, |
| 1553 | 1597 | tokenEndpoint: input.setupConfig.tokenEndpoint, |
| 1554 | 1598 | redirectUri, |
| 1555 | − oauthClientId: input.workspaceOauthClient.id, | |
| 1599 | + oauthClientId: input.scopeOauthClient.id, | |
| 1556 | 1600 | clientAuthentication: input.setupConfig.clientAuthentication, |
| 1557 | 1601 | scopes: [...normalizeScopes(input.setupConfig.scopes)], |
| 1558 | 1602 | headerName: input.setupConfig.headerName, |
| @@ -1577,7 +1621,7 @@ const startProviderOauthBatchCredentialSetup = (input: { · 18 unmodified lines | ||
| 1577 | 1621 | input.sourceStore, |
| 1578 | 1622 | input.targetSources[0]!.source, |
| 1579 | 1623 | { |
| 1580 | − actorAccountId: input.actorAccountId, | |
| 1624 | + actorScopeId: input.actorScopeId, | |
| 1581 | 1625 | status: "auth_required", |
| 1582 | 1626 | lastError: null, |
| 1583 | 1627 | }, |
| @@ -1587,7 +1631,7 @@ const startProviderOauthBatchCredentialSetup = (input: { · 3 unmodified lines | ||
| 1587 | 1631 | input.targetSources.slice(1), |
| 1588 | 1632 | (target) => |
| 1589 | 1633 | updateSourceStatus(input.sourceStore, target.source, { |
| 1590 | − actorAccountId: input.actorAccountId, | |
| 1634 | + actorScopeId: input.actorScopeId, | |
| 1591 | 1635 | status: "auth_required", |
| 1592 | 1636 | lastError: null, |
| 1593 | 1637 | }).pipe(Effect.asVoid), |
| @@ -1612,31 +1656,33 @@ const connectSourcesWithProviderRuntimeAuth = (input: { · 18 unmodified lines | ||
| 1612 | 1656 | executorState: ExecutorStateStoreShape; |
| 1613 | 1657 | sourceStore: RuntimeSourceStore; |
| 1614 | 1658 | sourceCatalogSync: RuntimeSourceCatalogSyncShape; |
| 1615 | − workspaceId: WorkspaceId; | |
| 1616 | − actorAccountId?: AccountId | null; | |
| 1659 | + scopeId: ScopeId; | |
| 1660 | + actorScopeId?: ScopeId | null; | |
| 1617 | 1661 | executionId?: SourceAuthSession["executionId"]; |
| 1618 | 1662 | interactionId?: SourceAuthSession["interactionId"]; |
| 1619 | 1663 | baseUrl?: string | null; |
| 1620 | 1664 | getLocalServerBaseUrl?: () => string | undefined; |
| 1621 | − workspaceOauthClient: ResolvedWorkspaceOauthClient; | |
| 1665 | + scopeOauthClient: ResolvedScopeOauthClient; | |
| 1622 | 1666 | targets: ReadonlyArray<RuntimeProviderAuthTarget>; |
| 1623 | −}): Effect.Effect<RuntimeProviderAuthResult, Error, WorkspaceStorageServices> => | |
| 1667 | + localScopeState?: RuntimeLocalScopeState; | |
| 1668 | +}): Effect.Effect<RuntimeProviderAuthResult, Error, ScopeStorageServices> => | |
| 1624 | 1669 | Effect.gen(function* () { |
| 1625 | 1670 | const setupConfig = yield* mergeRuntimeProviderAuthSetupConfig(input.targets); |
| 1626 | 1671 | const reusableGrant = yield* findReusableProviderGrant({ |
| 1627 | 1672 | executorState: input.executorState, |
| 1628 | − workspaceId: input.workspaceId, | |
| 1629 | − actorAccountId: input.actorAccountId, | |
| 1673 | + scopeId: input.scopeId, | |
| 1674 | + actorScopeId: input.actorScopeId, | |
| 1630 | 1675 | providerKey: setupConfig.providerKey, |
| 1631 | − oauthClientId: input.workspaceOauthClient.id, | |
| 1676 | + oauthClientId: input.scopeOauthClient.id, | |
| 1632 | 1677 | requiredScopes: setupConfig.scopes, |
| 1678 | + localScopeState: input.localScopeState, | |
| 1633 | 1679 | }); |
| 1634 | 1680 | |
| 1635 | 1681 | if (Option.isSome(reusableGrant)) { |
| 1636 | 1682 | const connectedSources = yield* attachProviderGrantToSources({ |
| 1637 | 1683 | sourceStore: input.sourceStore, |
| 1638 | 1684 | sourceCatalogSync: input.sourceCatalogSync, |
| 1639 | − actorAccountId: input.actorAccountId, | |
| 1685 | + actorScopeId: input.actorScopeId, | |
| 1640 | 1686 | grantId: reusableGrant.value.id, |
| 1641 | 1687 | providerKey: reusableGrant.value.providerKey, |
| 1642 | 1688 | headerName: reusableGrant.value.headerName, |
| @@ -1665,13 +1711,13 @@ const connectSourcesWithProviderRuntimeAuth = (input: { · 22 unmodified lines | ||
| 1665 | 1711 | const oauthRequired = yield* startProviderOauthBatchCredentialSetup({ |
| 1666 | 1712 | executorState: input.executorState, |
| 1667 | 1713 | sourceStore: input.sourceStore, |
| 1668 | − workspaceId: input.workspaceId, | |
| 1669 | − actorAccountId: input.actorAccountId, | |
| 1714 | + scopeId: input.scopeId, | |
| 1715 | + actorScopeId: input.actorScopeId, | |
| 1670 | 1716 | executionId: input.executionId, |
| 1671 | 1717 | interactionId: input.interactionId, |
| 1672 | 1718 | baseUrl, |
| 1673 | 1719 | redirectModeOverride: requestBaseUrl ? "app_callback" : undefined, |
| 1674 | − workspaceOauthClient: input.workspaceOauthClient, | |
| 1720 | + scopeOauthClient: input.scopeOauthClient, | |
| 1675 | 1721 | setupConfig, |
| 1676 | 1722 | targetSources: input.targets.map((target) => ({ |
| 1677 | 1723 | source: target.source, |
| @@ -1683,9 +1729,9 @@ const connectSourcesWithProviderRuntimeAuth = (input: { · 5 unmodified lines | ||
| 1683 | 1729 | input.targets, |
| 1684 | 1730 | (target) => |
| 1685 | 1731 | input.sourceStore.loadSourceById({ |
| 1686 | − workspaceId: target.source.workspaceId, | |
| 1732 | + scopeId: target.source.scopeId, | |
| 1687 | 1733 | sourceId: target.source.id, |
| 1688 | − actorAccountId: input.actorAccountId, | |
| 1734 | + actorScopeId: input.actorScopeId, | |
| 1689 | 1735 | }), |
| 1690 | 1736 | { discard: false }, |
| 1691 | 1737 | ); |
| @@ -1701,7 +1747,7 @@ const connectSourcesWithProviderRuntimeAuth = (input: { · 9 unmodified lines | ||
| 1701 | 1747 | const attachProviderGrantToSources = (input: { |
| 1702 | 1748 | sourceStore: RuntimeSourceStore; |
| 1703 | 1749 | sourceCatalogSync: RuntimeSourceCatalogSyncShape; |
| 1704 | − actorAccountId?: AccountId | null; | |
| 1750 | + actorScopeId?: ScopeId | null; | |
| 1705 | 1751 | grantId: ProviderAuthGrant["id"]; |
| 1706 | 1752 | providerKey: string; |
| 1707 | 1753 | headerName: string; |
| @@ -1710,13 +1756,13 @@ const attachProviderGrantToSources = (input: { · 2 unmodified lines | ||
| 1710 | 1756 | source: Source; |
| 1711 | 1757 | requiredScopes: ReadonlyArray<string>; |
| 1712 | 1758 | }>; |
| 1713 | −}): Effect.Effect<ReadonlyArray<Source>, Error, WorkspaceStorageServices> => | |
| 1759 | +}): Effect.Effect<ReadonlyArray<Source>, Error, ScopeStorageServices> => | |
| 1714 | 1760 | Effect.forEach( |
| 1715 | 1761 | input.targets, |
| 1716 | 1762 | (target) => |
| 1717 | 1763 | Effect.gen(function* () { |
| 1718 | 1764 | const connectedSource = yield* updateSourceStatus(input.sourceStore, target.source, { |
| 1719 | − actorAccountId: input.actorAccountId, | |
| 1765 | + actorScopeId: input.actorScopeId, | |
| 1720 | 1766 | status: "connected", |
| 1721 | 1767 | lastError: null, |
| 1722 | 1768 | auth: { |
| @@ -1731,7 +1777,7 @@ const attachProviderGrantToSources = (input: { · 8 unmodified lines | ||
| 1731 | 1777 | |
| 1732 | 1778 | yield* input.sourceCatalogSync.sync({ |
| 1733 | 1779 | source: connectedSource, |
| 1734 | − actorAccountId: input.actorAccountId, | |
| 1780 | + actorScopeId: input.actorScopeId, | |
| 1735 | 1781 | }); |
| 1736 | 1782 | |
| 1737 | 1783 | return connectedSource; |
| @@ -1742,18 +1788,18 @@ const attachProviderGrantToSources = (input: { · 4 unmodified lines | ||
| 1742 | 1788 | const removeProviderAuthGrantInternal = (input: { |
| 1743 | 1789 | executorState: ExecutorStateStoreShape; |
| 1744 | 1790 | sourceStore: RuntimeSourceStore; |
| 1745 | − workspaceId: WorkspaceId; | |
| 1791 | + scopeId: ScopeId; | |
| 1746 | 1792 | grantId: ProviderAuthGrant["id"]; |
| 1747 | 1793 | deleteSecretMaterial: DeleteSecretMaterial; |
| 1748 | −}): Effect.Effect<boolean, Error, WorkspaceStorageServices> => | |
| 1794 | +}): Effect.Effect<boolean, Error, ScopeStorageServices> => | |
| 1749 | 1795 | Effect.gen(function* () { |
| 1750 | 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 | 1798 | return false; |
| 1753 | 1799 | } |
| 1754 | 1800 | |
| 1755 | 1801 | const references = yield* listProviderGrantRefArtifacts(input.executorState, { |
| 1756 | − workspaceId: input.workspaceId, | |
| 1802 | + scopeId: input.scopeId, | |
| 1757 | 1803 | grantId: input.grantId, |
| 1758 | 1804 | }); |
| 1759 | 1805 | |
| @@ -1762,9 +1808,9 @@ const removeProviderAuthGrantInternal = (input: { · 2 unmodified lines | ||
| 1762 | 1808 | (artifact) => |
| 1763 | 1809 | Effect.gen(function* () { |
| 1764 | 1810 | const latestSource = yield* input.sourceStore.loadSourceById({ |
| 1765 | − workspaceId: artifact.workspaceId, | |
| 1811 | + scopeId: artifact.scopeId, | |
| 1766 | 1812 | sourceId: artifact.sourceId, |
| 1767 | − actorAccountId: artifact.actorAccountId, | |
| 1813 | + actorScopeId: artifact.actorScopeId, | |
| 1768 | 1814 | }).pipe( |
| 1769 | 1815 | Effect.catchAll(() => Effect.succeed(null)), |
| 1770 | 1816 | ); |
| @@ -1773,10 +1819,10 @@ const removeProviderAuthGrantInternal = (input: { · 2 unmodified lines | ||
| 1773 | 1819 | yield* removeAuthLeaseAndSecrets(input.executorState, { |
| 1774 | 1820 | authArtifactId: artifact.id, |
| 1775 | 1821 | }, input.deleteSecretMaterial); |
| 1776 | − yield* input.executorState.authArtifacts.removeByWorkspaceSourceAndActor({ | |
| 1777 | − workspaceId: artifact.workspaceId, | |
| 1822 | + yield* input.executorState.authArtifacts.removeByScopeSourceAndActor({ | |
| 1823 | + scopeId: artifact.scopeId, | |
| 1778 | 1824 | sourceId: artifact.sourceId, |
| 1779 | − actorAccountId: artifact.actorAccountId, | |
| 1825 | + actorScopeId: artifact.actorScopeId, | |
| 1780 | 1826 | slot: artifact.slot, |
| 1781 | 1827 | }); |
| 1782 | 1828 | return; |
| @@ -1790,7 +1836,7 @@ const removeProviderAuthGrantInternal = (input: { · 7 unmodified lines | ||
| 1790 | 1836 | importAuth: artifact.slot === "import" ? { kind: "none" } : latestSource.importAuth, |
| 1791 | 1837 | updatedAt: Date.now(), |
| 1792 | 1838 | }, { |
| 1793 | − actorAccountId: artifact.actorAccountId, | |
| 1839 | + actorScopeId: artifact.actorScopeId, | |
| 1794 | 1840 | }).pipe(Effect.asVoid); |
| 1795 | 1841 | }), |
| 1796 | 1842 | { discard: true }, |
| @@ -1809,8 +1855,8 @@ const connectMcpSourceInternal = (input: { · 12 unmodified lines | ||
| 1809 | 1855 | sourceCatalogSync: RuntimeSourceCatalogSyncShape; |
| 1810 | 1856 | getLocalServerBaseUrl?: () => string | undefined; |
| 1811 | 1857 | baseUrl?: string | null; |
| 1812 | − workspaceId: WorkspaceId; | |
| 1813 | − actorAccountId?: AccountId | null; | |
| 1858 | + scopeId: ScopeId; | |
| 1859 | + actorScopeId?: ScopeId | null; | |
| 1814 | 1860 | sourceId?: Source["id"] | null; |
| 1815 | 1861 | executionId?: SourceAuthSession["executionId"]; |
| 1816 | 1862 | interactionId?: SourceAuthSession["interactionId"]; |
| @@ -1827,7 +1873,7 @@ const connectMcpSourceInternal = (input: { · 10 unmodified lines | ||
| 1827 | 1873 | cwd?: string | null; |
| 1828 | 1874 | mcpDiscoveryElicitation?: McpDiscoveryElicitationContext; |
| 1829 | 1875 | resolveSecretMaterial: ResolveSecretMaterial; |
| 1830 | −}): Effect.Effect<McpSourceConnectResult, Error, WorkspaceStorageServices> => | |
| 1876 | +}): Effect.Effect<McpSourceConnectResult, Error, ScopeStorageServices> => | |
| 1831 | 1877 | Effect.gen(function* () { |
| 1832 | 1878 | const lookupEndpoint = input.sourceId |
| 1833 | 1879 | ? null |
| @@ -1840,9 +1886,9 @@ const connectMcpSourceInternal = (input: { · 6 unmodified lines | ||
| 1840 | 1886 | const existing = yield* ( |
| 1841 | 1887 | input.sourceId |
| 1842 | 1888 | ? input.sourceStore.loadSourceById({ |
| 1843 | − workspaceId: input.workspaceId, | |
| 1889 | + scopeId: input.scopeId, | |
| 1844 | 1890 | sourceId: input.sourceId, |
| 1845 | − actorAccountId: input.actorAccountId, | |
| 1891 | + actorScopeId: input.actorScopeId, | |
| 1846 | 1892 | }).pipe( |
| 1847 | 1893 | Effect.flatMap((source) => |
| 1848 | 1894 | sourceAdapterRequiresInteractiveConnect(source.kind) |
| @@ -1850,8 +1896,8 @@ const connectMcpSourceInternal = (input: { · 1 unmodified line | ||
| 1850 | 1896 | : Effect.fail(runtimeEffectError("sources/source-auth-service", `Expected MCP source, received ${source.kind}`)), |
| 1851 | 1897 | ), |
| 1852 | 1898 | ) |
| 1853 | − : input.sourceStore.loadSourcesInWorkspace(input.workspaceId, { | |
| 1854 | − actorAccountId: input.actorAccountId, | |
| 1899 | + : input.sourceStore.loadSourcesInScope(input.scopeId, { | |
| 1900 | + actorScopeId: input.actorScopeId, | |
| 1855 | 1901 | }).pipe( |
| 1856 | 1902 | Effect.map((sources) => |
| 1857 | 1903 | sources.find( |
| @@ -1943,7 +1989,7 @@ const connectMcpSourceInternal = (input: { · 85 unmodified lines | ||
| 1943 | 1989 | now, |
| 1944 | 1990 | }) |
| 1945 | 1991 | : yield* createSourceFromPayload({ |
| 1946 | − workspaceId: input.workspaceId, | |
| 1992 | + scopeId: input.scopeId, | |
| 1947 | 1993 | sourceId: SourceIdSchema.make(`src_${crypto.randomUUID()}`), |
| 1948 | 1994 | payload: { |
| 1949 | 1995 | name: chosenName, |
| @@ -1969,11 +2015,11 @@ const connectMcpSourceInternal = (input: { · 19 unmodified lines | ||
| 1969 | 2015 | }); |
| 1970 | 2016 | |
| 1971 | 2017 | const persistedDraft = yield* input.sourceStore.persistSource(draftSource, { |
| 1972 | − actorAccountId: input.actorAccountId, | |
| 2018 | + actorScopeId: input.actorScopeId, | |
| 1973 | 2019 | }); |
| 1974 | 2020 | yield* input.sourceCatalogSync.sync({ |
| 1975 | 2021 | source: persistedDraft, |
| 1976 | − actorAccountId: input.actorAccountId, | |
| 2022 | + actorScopeId: input.actorScopeId, | |
| 1977 | 2023 | }); |
| 1978 | 2024 | |
| 1979 | 2025 | const discovered = yield* Effect.either( |
| @@ -1988,7 +2034,7 @@ const connectMcpSourceInternal = (input: { · 8 unmodified lines | ||
| 1988 | 2034 | onRight: (result) => |
| 1989 | 2035 | Effect.gen(function* () { |
| 1990 | 2036 | const connected = yield* updateSourceStatus(input.sourceStore, persistedDraft, { |
| 1991 | − actorAccountId: input.actorAccountId, | |
| 2037 | + actorScopeId: input.actorScopeId, | |
| 1992 | 2038 | status: "connected", |
| 1993 | 2039 | lastError: null, |
| 1994 | 2040 | auth: { kind: "none" }, |
| @@ -2003,7 +2049,7 @@ const connectMcpSourceInternal = (input: { · 8 unmodified lines | ||
| 2003 | 2049 | return yield* Either.match(indexed, { |
| 2004 | 2050 | onLeft: (error) => |
| 2005 | 2051 | updateSourceStatus(input.sourceStore, connected, { |
| 2006 | − actorAccountId: input.actorAccountId, | |
| 2052 | + actorScopeId: input.actorScopeId, | |
| 2007 | 2053 | status: "error", |
| 2008 | 2054 | lastError: error.message, |
| 2009 | 2055 | }).pipe( |
| @@ -2031,7 +2077,7 @@ const connectMcpSourceInternal = (input: { · 21 unmodified lines | ||
| 2031 | 2077 | const state = crypto.randomUUID(); |
| 2032 | 2078 | const redirectUrl = resolveSourceCredentialOauthCompleteUrl({ |
| 2033 | 2079 | baseUrl: localServerBaseUrl, |
| 2034 | − workspaceId: input.workspaceId, | |
| 2080 | + scopeId: input.scopeId, | |
| 2035 | 2081 | sourceId: persistedDraft.id, |
| 2036 | 2082 | }); |
| 2037 | 2083 | const oauthStart = yield* startMcpOAuthAuthorization({ |
| @@ -2041,7 +2087,7 @@ const connectMcpSourceInternal = (input: { · 3 unmodified lines | ||
| 2041 | 2087 | }); |
| 2042 | 2088 | |
| 2043 | 2089 | const authRequiredSource = yield* updateSourceStatus(input.sourceStore, persistedDraft, { |
| 2044 | − actorAccountId: input.actorAccountId, | |
| 2090 | + actorScopeId: input.actorScopeId, | |
| 2045 | 2091 | status: "auth_required", |
| 2046 | 2092 | lastError: null, |
| 2047 | 2093 | }); |
| @@ -2049,9 +2095,9 @@ const connectMcpSourceInternal = (input: { · 1 unmodified line | ||
| 2049 | 2095 | const sessionNow = Date.now(); |
| 2050 | 2096 | yield* input.executorState.sourceAuthSessions.upsert({ |
| 2051 | 2097 | id: sessionId, |
| 2052 | − workspaceId: input.workspaceId, | |
| 2098 | + scopeId: input.scopeId, | |
| 2053 | 2099 | sourceId: authRequiredSource.id, |
| 2054 | − actorAccountId: input.actorAccountId ?? null, | |
| 2100 | + actorScopeId: input.actorScopeId ?? null, | |
| 2055 | 2101 | credentialSlot: "runtime", |
| 2056 | 2102 | executionId: input.executionId ?? null, |
| 2057 | 2103 | interactionId: input.interactionId ?? null, |
| @@ -2095,16 +2141,17 @@ const addExecutorHttpSource = (input: { · 37 unmodified lines | ||
| 2095 | 2141 | resolveSecretMaterial: ResolveSecretMaterial; |
| 2096 | 2142 | getLocalServerBaseUrl?: () => string | undefined; |
| 2097 | 2143 | baseUrl?: string | null; |
| 2098 | −}): Effect.Effect<ExecutorSourceAddResult, Error, WorkspaceStorageServices> => | |
| 2144 | + localScopeState?: RuntimeLocalScopeState; | |
| 2145 | +}): Effect.Effect<ExecutorSourceAddResult, Error, ScopeStorageServices> => | |
| 2099 | 2146 | Effect.gen(function* () { |
| 2100 | 2147 | const normalizedEndpoint = normalizeEndpoint(input.sourceInput.endpoint); |
| 2101 | 2148 | const normalizedSpecUrl = input.sourceInput.kind === "openapi" |
| 2102 | 2149 | ? normalizeEndpoint(input.sourceInput.specUrl) |
| 2103 | 2150 | : null; |
| 2104 | − const existingSources = yield* input.sourceStore.loadSourcesInWorkspace( | |
| 2105 | − input.sourceInput.workspaceId, | |
| 2151 | + const existingSources = yield* input.sourceStore.loadSourcesInScope( | |
| 2152 | + input.sourceInput.scopeId, | |
| 2106 | 2153 | { |
| 2107 | − actorAccountId: input.sourceInput.actorAccountId, | |
| 2154 | + actorScopeId: input.sourceInput.actorScopeId, | |
| 2108 | 2155 | }, |
| 2109 | 2156 | ); |
| 2110 | 2157 | const existing = existingSources.find((source) => { |
| @@ -2175,7 +2222,7 @@ const addExecutorHttpSource = (input: { · 64 unmodified lines | ||
| 2175 | 2222 | now, |
| 2176 | 2223 | }) |
| 2177 | 2224 | : yield* createSourceFromPayload({ |
| 2178 | − workspaceId: input.sourceInput.workspaceId, | |
| 2225 | + scopeId: input.sourceInput.scopeId, | |
| 2179 | 2226 | sourceId: SourceIdSchema.make(`src_${crypto.randomUUID()}`), |
| 2180 | 2227 | payload: { |
| 2181 | 2228 | name: chosenName, |
| @@ -2200,7 +2247,7 @@ const addExecutorHttpSource = (input: { · 18 unmodified lines | ||
| 2200 | 2247 | }); |
| 2201 | 2248 | |
| 2202 | 2249 | const persistedDraft = yield* input.sourceStore.persistSource(draftSource, { |
| 2203 | − actorAccountId: input.sourceInput.actorAccountId, | |
| 2250 | + actorScopeId: input.sourceInput.actorScopeId, | |
| 2204 | 2251 | }); |
| 2205 | 2252 | |
| 2206 | 2253 | if (shouldPromptForExecutorHttpRuntimeCredentialSetup({ |
| @@ -2215,7 +2262,7 @@ const addExecutorHttpSource = (input: { · 8 unmodified lines | ||
| 2215 | 2262 | executorState: input.executorState, |
| 2216 | 2263 | sourceStore: input.sourceStore, |
| 2217 | 2264 | source: persistedDraft, |
| 2218 | − actorAccountId: input.sourceInput.actorAccountId, | |
| 2265 | + actorScopeId: input.sourceInput.actorScopeId, | |
| 2219 | 2266 | executionId: input.sourceInput.executionId, |
| 2220 | 2267 | interactionId: input.sourceInput.interactionId, |
| 2221 | 2268 | baseUrl, |
| @@ -2228,7 +2275,7 @@ const addExecutorHttpSource = (input: { · 6 unmodified lines | ||
| 2228 | 2275 | } |
| 2229 | 2276 | |
| 2230 | 2277 | const authRequiredSource = yield* updateSourceStatus(input.sourceStore, persistedDraft, { |
| 2231 | − actorAccountId: input.sourceInput.actorAccountId, | |
| 2278 | + actorScopeId: input.sourceInput.actorScopeId, | |
| 2232 | 2279 | status: "auth_required", |
| 2233 | 2280 | lastError: null, |
| 2234 | 2281 | }); |
| @@ -2246,7 +2293,7 @@ const addExecutorHttpSource = (input: { · 11 unmodified lines | ||
| 2246 | 2293 | ...persistedDraft, |
| 2247 | 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 | 2301 | onLeft: (error) => |
| 2255 | 2302 | isSourceCredentialRequiredError(error) |
| 2256 | 2303 | ? updateSourceStatus(input.sourceStore, persistedDraft, { |
| 2257 | − actorAccountId: input.sourceInput.actorAccountId, | |
| 2304 | + actorScopeId: input.sourceInput.actorScopeId, | |
| 2258 | 2305 | status: "auth_required", |
| 2259 | 2306 | lastError: null, |
| 2260 | 2307 | }).pipe( |
| @@ -2267,7 +2314,7 @@ const addExecutorHttpSource = (input: { · 6 unmodified lines | ||
| 2267 | 2314 | ), |
| 2268 | 2315 | ) |
| 2269 | 2316 | : updateSourceStatus(input.sourceStore, persistedDraft, { |
| 2270 | − actorAccountId: input.sourceInput.actorAccountId, | |
| 2317 | + actorScopeId: input.sourceInput.actorScopeId, | |
| 2271 | 2318 | status: "error", |
| 2272 | 2319 | lastError: error.message, |
| 2273 | 2320 | }).pipe( |
| @@ -2275,7 +2322,7 @@ const addExecutorHttpSource = (input: { · 1 unmodified line | ||
| 2275 | 2322 | ), |
| 2276 | 2323 | onRight: () => |
| 2277 | 2324 | updateSourceStatus(input.sourceStore, persistedDraft, { |
| 2278 | − actorAccountId: input.sourceInput.actorAccountId, | |
| 2325 | + actorScopeId: input.sourceInput.actorScopeId, | |
| 2279 | 2326 | status: "connected", |
| 2280 | 2327 | lastError: null, |
| 2281 | 2328 | }).pipe( |
| @@ -2308,7 +2355,8 @@ const addExecutorGoogleDiscoverySource = (input: { · 26 unmodified lines | ||
| 2308 | 2355 | resolveSecretMaterial: ResolveSecretMaterial; |
| 2309 | 2356 | getLocalServerBaseUrl?: () => string | undefined; |
| 2310 | 2357 | baseUrl?: string | null; |
| 2311 | −}): Effect.Effect<ExecutorSourceAddResult, Error, WorkspaceStorageServices> => | |
| 2358 | + localScopeState?: RuntimeLocalScopeState; | |
| 2359 | +}): Effect.Effect<ExecutorSourceAddResult, Error, ScopeStorageServices> => | |
| 2312 | 2360 | Effect.gen(function* () { |
| 2313 | 2361 | const normalizedService = input.sourceInput.service.trim(); |
| 2314 | 2362 | const normalizedVersion = input.sourceInput.version.trim(); |
| @@ -2316,10 +2364,10 @@ const addExecutorGoogleDiscoverySource = (input: { · 1 unmodified line | ||
| 2316 | 2364 | trimOrNull(input.sourceInput.discoveryUrl) |
| 2317 | 2365 | ?? defaultGoogleDiscoveryUrl(normalizedService, normalizedVersion), |
| 2318 | 2366 | ); |
| 2319 | − const existingSources = yield* input.sourceStore.loadSourcesInWorkspace( | |
| 2320 | − input.sourceInput.workspaceId, | |
| 2367 | + const existingSources = yield* input.sourceStore.loadSourcesInScope( | |
| 2368 | + input.sourceInput.scopeId, | |
| 2321 | 2369 | { |
| 2322 | − actorAccountId: input.sourceInput.actorAccountId, | |
| 2370 | + actorScopeId: input.sourceInput.actorScopeId, | |
| 2323 | 2371 | }, |
| 2324 | 2372 | ); |
| 2325 | 2373 | const existing = existingSources.find((source) => { |
| @@ -2397,7 +2445,7 @@ const addExecutorGoogleDiscoverySource = (input: { · 71 unmodified lines | ||
| 2397 | 2445 | now, |
| 2398 | 2446 | }) |
| 2399 | 2447 | : yield* createSourceFromPayload({ |
| 2400 | − workspaceId: input.sourceInput.workspaceId, | |
| 2448 | + scopeId: input.sourceInput.scopeId, | |
| 2401 | 2449 | sourceId: SourceIdSchema.make(`src_${crypto.randomUUID()}`), |
| 2402 | 2450 | payload: { |
| 2403 | 2451 | name: chosenName, |
| @@ -2421,7 +2469,7 @@ const addExecutorGoogleDiscoverySource = (input: { · 17 unmodified lines | ||
| 2421 | 2469 | }); |
| 2422 | 2470 | |
| 2423 | 2471 | const persistedDraft = yield* input.sourceStore.persistSource(draftSource, { |
| 2424 | − actorAccountId: input.sourceInput.actorAccountId, | |
| 2472 | + actorScopeId: input.sourceInput.actorScopeId, | |
| 2425 | 2473 | }); |
| 2426 | 2474 | const googleAdapter = getSourceAdapterForSource(persistedDraft); |
| 2427 | 2475 | const providerAuthTarget = yield* resolveRuntimeProviderAuthTarget(persistedDraft); |
| @@ -2431,18 +2479,19 @@ const addExecutorGoogleDiscoverySource = (input: { · 3 unmodified lines | ||
| 2431 | 2479 | && input.sourceInput.auth === undefined |
| 2432 | 2480 | && persistedDraft.auth.kind === "none" |
| 2433 | 2481 | ) { |
| 2434 | − let workspaceOauthClient: ResolvedWorkspaceOauthClient | null = null; | |
| 2435 | − if (input.sourceInput.workspaceOauthClientId) { | |
| 2436 | − workspaceOauthClient = yield* resolveWorkspaceOauthClientById({ | |
| 2482 | + let scopeOauthClient: ResolvedScopeOauthClient | null = null; | |
| 2483 | + if (input.sourceInput.scopeOauthClientId) { | |
| 2484 | + scopeOauthClient = yield* resolveScopeOauthClientById({ | |
| 2437 | 2485 | executorState: input.executorState, |
| 2438 | − workspaceId: persistedDraft.workspaceId, | |
| 2439 | − oauthClientId: input.sourceInput.workspaceOauthClientId, | |
| 2486 | + scopeId: persistedDraft.scopeId, | |
| 2487 | + oauthClientId: input.sourceInput.scopeOauthClientId, | |
| 2440 | 2488 | providerKey: providerAuthTarget.setupConfig.providerKey, |
| 2489 | + localScopeState: input.localScopeState, | |
| 2441 | 2490 | }); |
| 2442 | 2491 | } else if (input.sourceInput.oauthClient) { |
| 2443 | − workspaceOauthClient = yield* createWorkspaceOauthClient({ | |
| 2492 | + scopeOauthClient = yield* createScopeOauthClient({ | |
| 2444 | 2493 | executorState: input.executorState, |
| 2445 | − workspaceId: persistedDraft.workspaceId, | |
| 2494 | + scopeId: persistedDraft.scopeId, | |
| 2446 | 2495 | providerKey: providerAuthTarget.setupConfig.providerKey, |
| 2447 | 2496 | oauthClient: input.sourceInput.oauthClient, |
| 2448 | 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 | 2504 | return yield* runtimeEffectError( |
| 2456 | 2505 | "sources/source-auth-service", |
| 2457 | 2506 | `${providerAuthTarget.setupConfig.providerKey} shared auth requires a workspace OAuth client`, |
| @@ -2462,14 +2511,15 @@ const addExecutorGoogleDiscoverySource = (input: { · 4 unmodified lines | ||
| 2462 | 2511 | executorState: input.executorState, |
| 2463 | 2512 | sourceStore: input.sourceStore, |
| 2464 | 2513 | sourceCatalogSync: input.sourceCatalogSync, |
| 2465 | − workspaceId: persistedDraft.workspaceId, | |
| 2466 | − actorAccountId: input.sourceInput.actorAccountId, | |
| 2514 | + scopeId: persistedDraft.scopeId, | |
| 2515 | + actorScopeId: input.sourceInput.actorScopeId, | |
| 2467 | 2516 | executionId: input.sourceInput.executionId, |
| 2468 | 2517 | interactionId: input.sourceInput.interactionId, |
| 2469 | 2518 | baseUrl: input.baseUrl, |
| 2470 | 2519 | getLocalServerBaseUrl: input.getLocalServerBaseUrl, |
| 2471 | − workspaceOauthClient, | |
| 2520 | + scopeOauthClient, | |
| 2472 | 2521 | targets: [providerAuthTarget], |
| 2522 | + localScopeState: input.localScopeState, | |
| 2473 | 2523 | }); |
| 2474 | 2524 | |
| 2475 | 2525 | return providerAuthResult.kind === "connected" |
| @@ -2507,7 +2557,7 @@ const addExecutorGoogleDiscoverySource = (input: { · 31 unmodified lines | ||
| 2507 | 2557 | executorState: input.executorState, |
| 2508 | 2558 | sourceStore: input.sourceStore, |
| 2509 | 2559 | source: persistedDraft, |
| 2510 | − actorAccountId: input.sourceInput.actorAccountId, | |
| 2560 | + actorScopeId: input.sourceInput.actorScopeId, | |
| 2511 | 2561 | executionId: input.sourceInput.executionId, |
| 2512 | 2562 | interactionId: input.sourceInput.interactionId, |
| 2513 | 2563 | baseUrl, |
| @@ -2520,7 +2570,7 @@ const addExecutorGoogleDiscoverySource = (input: { · 6 unmodified lines | ||
| 2520 | 2570 | } |
| 2521 | 2571 | |
| 2522 | 2572 | const authRequiredSource = yield* updateSourceStatus(input.sourceStore, persistedDraft, { |
| 2523 | − actorAccountId: input.sourceInput.actorAccountId, | |
| 2573 | + actorScopeId: input.sourceInput.actorScopeId, | |
| 2524 | 2574 | status: "auth_required", |
| 2525 | 2575 | lastError: null, |
| 2526 | 2576 | }); |
| @@ -2538,7 +2588,7 @@ const addExecutorGoogleDiscoverySource = (input: { · 11 unmodified lines | ||
| 2538 | 2588 | ...persistedDraft, |
| 2539 | 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 | 2596 | onLeft: (error) => |
| 2547 | 2597 | isSourceCredentialRequiredError(error) |
| 2548 | 2598 | ? updateSourceStatus(input.sourceStore, persistedDraft, { |
| 2549 | − actorAccountId: input.sourceInput.actorAccountId, | |
| 2599 | + actorScopeId: input.sourceInput.actorScopeId, | |
| 2550 | 2600 | status: "auth_required", |
| 2551 | 2601 | lastError: null, |
| 2552 | 2602 | }).pipe( |
| @@ -2559,7 +2609,7 @@ const addExecutorGoogleDiscoverySource = (input: { · 6 unmodified lines | ||
| 2559 | 2609 | ), |
| 2560 | 2610 | ) |
| 2561 | 2611 | : updateSourceStatus(input.sourceStore, persistedDraft, { |
| 2562 | − actorAccountId: input.sourceInput.actorAccountId, | |
| 2612 | + actorScopeId: input.sourceInput.actorScopeId, | |
| 2563 | 2613 | status: "error", |
| 2564 | 2614 | lastError: error.message, |
| 2565 | 2615 | }).pipe( |
| @@ -2567,7 +2617,7 @@ const addExecutorGoogleDiscoverySource = (input: { · 1 unmodified line | ||
| 2567 | 2617 | ), |
| 2568 | 2618 | onRight: () => |
| 2569 | 2619 | updateSourceStatus(input.sourceStore, persistedDraft, { |
| 2570 | − actorAccountId: input.sourceInput.actorAccountId, | |
| 2620 | + actorScopeId: input.sourceInput.actorScopeId, | |
| 2571 | 2621 | status: "connected", |
| 2572 | 2622 | lastError: null, |
| 2573 | 2623 | }).pipe( |
| @@ -2587,16 +2637,17 @@ const connectGoogleDiscoveryBatchInternal = (input: { · 13 unmodified lines | ||
| 2587 | 2637 | sourceCatalogSync: RuntimeSourceCatalogSyncShape; |
| 2588 | 2638 | sourceInput: ConnectGoogleDiscoveryBatchInput; |
| 2589 | 2639 | getLocalServerBaseUrl?: () => string | undefined; |
| 2590 | −}): Effect.Effect<ConnectGoogleDiscoveryBatchResult, Error, WorkspaceStorageServices> => | |
| 2640 | + localScopeState?: RuntimeLocalScopeState; | |
| 2641 | +}): Effect.Effect<ConnectGoogleDiscoveryBatchResult, Error, ScopeStorageServices> => | |
| 2591 | 2642 | Effect.gen(function* () { |
| 2592 | 2643 | if (input.sourceInput.sources.length === 0) { |
| 2593 | 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( | |
| 2597 | − input.sourceInput.workspaceId, | |
| 2647 | + const existingSources = yield* input.sourceStore.loadSourcesInScope( | |
| 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 | 2715 | now, |
| 2665 | 2716 | }) |
| 2666 | 2717 | : yield* createSourceFromPayload({ |
| 2667 | − workspaceId: input.sourceInput.workspaceId, | |
| 2718 | + scopeId: input.sourceInput.scopeId, | |
| 2668 | 2719 | sourceId: SourceIdSchema.make(`src_${crypto.randomUUID()}`), |
| 2669 | 2720 | payload: { |
| 2670 | 2721 | name: chosenName, |
| @@ -2688,7 +2739,7 @@ const connectGoogleDiscoveryBatchInternal = (input: { · 17 unmodified lines | ||
| 2688 | 2739 | }); |
| 2689 | 2740 | |
| 2690 | 2741 | const persistedDraft = yield* input.sourceStore.persistSource(draftSource, { |
| 2691 | − actorAccountId: input.sourceInput.actorAccountId, | |
| 2742 | + actorScopeId: input.sourceInput.actorScopeId, | |
| 2692 | 2743 | }); |
| 2693 | 2744 | const providerAuthTarget = yield* resolveRuntimeProviderAuthTarget(persistedDraft); |
| 2694 | 2745 | if (providerAuthTarget === null) { |
| @@ -2700,28 +2751,30 @@ const connectGoogleDiscoveryBatchInternal = (input: { · 5 unmodified lines | ||
| 2700 | 2751 | { discard: false }, |
| 2701 | 2752 | ); |
| 2702 | 2753 | |
| 2703 | − const workspaceOauthClient = yield* resolveWorkspaceOauthClientById({ | |
| 2754 | + const scopeOauthClient = yield* resolveScopeOauthClientById({ | |
| 2704 | 2755 | executorState: input.executorState, |
| 2705 | − workspaceId: input.sourceInput.workspaceId, | |
| 2706 | − oauthClientId: input.sourceInput.workspaceOauthClientId, | |
| 2756 | + scopeId: input.sourceInput.scopeId, | |
| 2757 | + oauthClientId: input.sourceInput.scopeOauthClientId, | |
| 2707 | 2758 | providerKey: persistedTargets[0]!.setupConfig.providerKey, |
| 2759 | + localScopeState: input.localScopeState, | |
| 2708 | 2760 | }); |
| 2709 | − if (workspaceOauthClient === null) { | |
| 2710 | − return yield* runtimeEffectError("sources/source-auth-service", `Workspace OAuth client not found: ${input.sourceInput.workspaceOauthClientId}`); | |
| 2761 | + if (scopeOauthClient === null) { | |
| 2762 | + return yield* runtimeEffectError("sources/source-auth-service", `Scope OAuth client not found: ${input.sourceInput.scopeOauthClientId}`); | |
| 2711 | 2763 | } |
| 2712 | 2764 | |
| 2713 | 2765 | const providerAuthResult = yield* connectSourcesWithProviderRuntimeAuth({ |
| 2714 | 2766 | executorState: input.executorState, |
| 2715 | 2767 | sourceStore: input.sourceStore, |
| 2716 | 2768 | sourceCatalogSync: input.sourceCatalogSync, |
| 2717 | − workspaceId: input.sourceInput.workspaceId, | |
| 2718 | − actorAccountId: input.sourceInput.actorAccountId, | |
| 2769 | + scopeId: input.sourceInput.scopeId, | |
| 2770 | + actorScopeId: input.sourceInput.actorScopeId, | |
| 2719 | 2771 | executionId: input.sourceInput.executionId, |
| 2720 | 2772 | interactionId: input.sourceInput.interactionId, |
| 2721 | 2773 | baseUrl: input.sourceInput.baseUrl, |
| 2722 | 2774 | getLocalServerBaseUrl: input.getLocalServerBaseUrl, |
| 2723 | − workspaceOauthClient, | |
| 2775 | + scopeOauthClient, | |
| 2724 | 2776 | targets: persistedTargets, |
| 2777 | + localScopeState: input.localScopeState, | |
| 2725 | 2778 | }); |
| 2726 | 2779 | |
| 2727 | 2780 | if (providerAuthResult.kind === "connected") { |
| @@ -2749,10 +2802,10 @@ const connectGoogleDiscoveryBatchInternal = (input: { · 21 unmodified lines | ||
| 2749 | 2802 | |
| 2750 | 2803 | type RuntimeSourceAuthServiceShape = { |
| 2751 | 2804 | getSourceById: (input: { |
| 2752 | − workspaceId: WorkspaceId; | |
| 2805 | + scopeId: ScopeId; | |
| 2753 | 2806 | sourceId: Source["id"]; |
| 2754 | − actorAccountId?: AccountId | null; | |
| 2755 | − }) => Effect.Effect<Source, Error, WorkspaceStorageServices>; | |
| 2807 | + actorScopeId?: ScopeId | null; | |
| 2808 | + }) => Effect.Effect<Source, Error, ScopeStorageServices>; | |
| 2756 | 2809 | getLocalServerBaseUrl: () => string | null; |
| 2757 | 2810 | storeSecretMaterial: (input: { |
| 2758 | 2811 | purpose: SecretMaterialPurpose; |
| @@ -2764,28 +2817,28 @@ type RuntimeSourceAuthServiceShape = { · 5 unmodified lines | ||
| 2764 | 2817 | mcpDiscoveryElicitation?: McpDiscoveryElicitationContext; |
| 2765 | 2818 | baseUrl?: string | null; |
| 2766 | 2819 | }, |
| 2767 | − ) => Effect.Effect<ExecutorSourceAddResult, Error, WorkspaceStorageServices>; | |
| 2820 | + ) => Effect.Effect<ExecutorSourceAddResult, Error, ScopeStorageServices>; | |
| 2768 | 2821 | connectGoogleDiscoveryBatch: ( |
| 2769 | 2822 | input: ConnectGoogleDiscoveryBatchInput, |
| 2770 | − ) => Effect.Effect<ConnectGoogleDiscoveryBatchResult, Error, WorkspaceStorageServices>; | |
| 2823 | + ) => Effect.Effect<ConnectGoogleDiscoveryBatchResult, Error, ScopeStorageServices>; | |
| 2771 | 2824 | connectMcpSource: ( |
| 2772 | 2825 | input: ConnectMcpSourceInput, |
| 2773 | − ) => Effect.Effect<McpSourceConnectResult, Error, WorkspaceStorageServices>; | |
| 2774 | − listWorkspaceOauthClients: (input: { | |
| 2775 | − workspaceId: WorkspaceId; | |
| 2826 | + ) => Effect.Effect<McpSourceConnectResult, Error, ScopeStorageServices>; | |
| 2827 | + listScopeOauthClients: (input: { | |
| 2828 | + scopeId: ScopeId; | |
| 2776 | 2829 | providerKey: string; |
| 2777 | − }) => Effect.Effect<readonly WorkspaceOauthClient[], Error, WorkspaceStorageServices>; | |
| 2778 | − createWorkspaceOauthClient: ( | |
| 2779 | − input: CreateWorkspaceOauthClientInput, | |
| 2780 | − ) => Effect.Effect<WorkspaceOauthClient, Error, WorkspaceStorageServices>; | |
| 2781 | − removeWorkspaceOauthClient: (input: { | |
| 2782 | − workspaceId: WorkspaceId; | |
| 2783 | − oauthClientId: WorkspaceOauthClient["id"]; | |
| 2784 | − }) => Effect.Effect<boolean, Error, WorkspaceStorageServices>; | |
| 2830 | + }) => Effect.Effect<readonly ScopeOauthClient[], Error, ScopeStorageServices>; | |
| 2831 | + createScopeOauthClient: ( | |
| 2832 | + input: CreateScopeOauthClientInput, | |
| 2833 | + ) => Effect.Effect<ScopeOauthClient, Error, ScopeStorageServices>; | |
| 2834 | + removeScopeOauthClient: (input: { | |
| 2835 | + scopeId: ScopeId; | |
| 2836 | + oauthClientId: ScopeOauthClient["id"]; | |
| 2837 | + }) => Effect.Effect<boolean, Error, ScopeStorageServices>; | |
| 2785 | 2838 | removeProviderAuthGrant: (input: { |
| 2786 | − workspaceId: WorkspaceId; | |
| 2839 | + scopeId: ScopeId; | |
| 2787 | 2840 | grantId: ProviderAuthGrant["id"]; |
| 2788 | − }) => Effect.Effect<boolean, Error, WorkspaceStorageServices>; | |
| 2841 | + }) => Effect.Effect<boolean, Error, ScopeStorageServices>; | |
| 2789 | 2842 | startSourceOAuthSession: ( |
| 2790 | 2843 | input: StartSourceOAuthSessionInput, |
| 2791 | 2844 | ) => Effect.Effect<StartSourceOAuthSessionResult, Error, never>; |
| @@ -2794,24 +2847,24 @@ type RuntimeSourceAuthServiceShape = { · 2 unmodified lines | ||
| 2794 | 2847 | code?: string | null; |
| 2795 | 2848 | error?: string | null; |
| 2796 | 2849 | errorDescription?: string | null; |
| 2797 | − }) => Effect.Effect<CompleteSourceOAuthSessionResult, Error, WorkspaceStorageServices>; | |
| 2850 | + }) => Effect.Effect<CompleteSourceOAuthSessionResult, Error, ScopeStorageServices>; | |
| 2798 | 2851 | completeProviderOauthCallback: (input: { |
| 2799 | − workspaceId: WorkspaceId; | |
| 2800 | − actorAccountId?: AccountId | null; | |
| 2852 | + scopeId: ScopeId; | |
| 2853 | + actorScopeId?: ScopeId | null; | |
| 2801 | 2854 | state: string; |
| 2802 | 2855 | code?: string | null; |
| 2803 | 2856 | error?: string | null; |
| 2804 | 2857 | errorDescription?: string | null; |
| 2805 | − }) => Effect.Effect<CompleteProviderOauthCallbackResult, Error, WorkspaceStorageServices>; | |
| 2858 | + }) => Effect.Effect<CompleteProviderOauthCallbackResult, Error, ScopeStorageServices>; | |
| 2806 | 2859 | completeSourceCredentialSetup: (input: { |
| 2807 | − workspaceId: WorkspaceId; | |
| 2860 | + scopeId: ScopeId; | |
| 2808 | 2861 | sourceId: Source["id"]; |
| 2809 | − actorAccountId?: AccountId | null; | |
| 2862 | + actorScopeId?: ScopeId | null; | |
| 2810 | 2863 | state: string; |
| 2811 | 2864 | code?: string | null; |
| 2812 | 2865 | error?: string | null; |
| 2813 | 2866 | errorDescription?: string | null; |
| 2814 | − }) => Effect.Effect<CompleteSourceCredentialSetupResult, Error, WorkspaceStorageServices>; | |
| 2867 | + }) => Effect.Effect<CompleteSourceCredentialSetupResult, Error, ScopeStorageServices>; | |
| 2815 | 2868 | }; |
| 2816 | 2869 | |
| 2817 | 2870 | type RuntimeSourceAuthDependencies = { |
| @@ -2823,10 +2876,10 @@ type RuntimeSourceAuthDependencies = { · 5 unmodified lines | ||
| 2823 | 2876 | storeSecretMaterial: StoreSecretMaterial; |
| 2824 | 2877 | deleteSecretMaterial: DeleteSecretMaterial; |
| 2825 | 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 | 2883 | effect: Effect.Effect<A, E, R>, |
| 2831 | 2884 | ) => Effect.Effect<A, E, R>; |
| 2832 | 2885 | |
| @@ -2836,9 +2889,9 @@ type RuntimeSourceConnectionServiceShape = Pick< · 3 unmodified lines | ||
| 2836 | 2889 | | "addExecutorSource" |
| 2837 | 2890 | | "connectGoogleDiscoveryBatch" |
| 2838 | 2891 | | "connectMcpSource" |
| 2839 | − | "listWorkspaceOauthClients" | |
| 2840 | − | "createWorkspaceOauthClient" | |
| 2841 | − | "removeWorkspaceOauthClient" | |
| 2892 | + | "listScopeOauthClients" | |
| 2893 | + | "createScopeOauthClient" | |
| 2894 | + | "removeScopeOauthClient" | |
| 2842 | 2895 | | "removeProviderAuthGrant" |
| 2843 | 2896 | >; |
| 2844 | 2897 | |
| @@ -2852,24 +2905,24 @@ type RuntimeSourceOAuthSessionServiceShape = Pick< · 7 unmodified lines | ||
| 2852 | 2905 | |
| 2853 | 2906 | const createRuntimeSourceConnectionService = ( |
| 2854 | 2907 | input: RuntimeSourceAuthDependencies, |
| 2855 | − provideLocalWorkspace: ProvideLocalWorkspace, | |
| 2908 | + provideLocalWorkspace: ProvideLocalScope, | |
| 2856 | 2909 | ): RuntimeSourceConnectionServiceShape => { |
| 2857 | 2910 | const mirrorLocalSourceResult = ( |
| 2858 | 2911 | result: ExecutorSourceAddResult, |
| 2859 | − ): Effect.Effect<ExecutorSourceAddResult, Error, WorkspaceStorageServices> => | |
| 2912 | + ): Effect.Effect<ExecutorSourceAddResult, Error, ScopeStorageServices> => | |
| 2860 | 2913 | Effect.succeed(result); |
| 2861 | 2914 | const mirrorLocalMcpSourceResult = ( |
| 2862 | 2915 | result: McpSourceConnectResult, |
| 2863 | − ): Effect.Effect<McpSourceConnectResult, Error, WorkspaceStorageServices> => | |
| 2916 | + ): Effect.Effect<McpSourceConnectResult, Error, ScopeStorageServices> => | |
| 2864 | 2917 | Effect.succeed(result); |
| 2865 | 2918 | |
| 2866 | 2919 | return { |
| 2867 | − getSourceById: ({ workspaceId, sourceId, actorAccountId }) => | |
| 2920 | + getSourceById: ({ scopeId, sourceId, actorScopeId }) => | |
| 2868 | 2921 | provideLocalWorkspace( |
| 2869 | 2922 | input.sourceStore.loadSourceById({ |
| 2870 | − workspaceId, | |
| 2923 | + scopeId, | |
| 2871 | 2924 | sourceId, |
| 2872 | − actorAccountId, | |
| 2925 | + actorScopeId, | |
| 2873 | 2926 | }), |
| 2874 | 2927 | ), |
| 2875 | 2928 | |
| @@ -2886,6 +2939,7 @@ const createRuntimeSourceConnectionService = ( · 10 unmodified lines | ||
| 2886 | 2939 | resolveSecretMaterial: input.resolveSecretMaterial, |
| 2887 | 2940 | getLocalServerBaseUrl: input.getLocalServerBaseUrl, |
| 2888 | 2941 | baseUrl: options?.baseUrl, |
| 2942 | + localScopeState: input.localScopeState, | |
| 2889 | 2943 | }) |
| 2890 | 2944 | : isExecutorHttpEndpointSourceInput(sourceInput) |
| 2891 | 2945 | ? addExecutorHttpSource({ |
| @@ -2898,6 +2952,7 @@ const createRuntimeSourceConnectionService = ( · 6 unmodified lines | ||
| 2898 | 2952 | resolveSecretMaterial: input.resolveSecretMaterial, |
| 2899 | 2953 | getLocalServerBaseUrl: input.getLocalServerBaseUrl, |
| 2900 | 2954 | baseUrl: options?.baseUrl, |
| 2955 | + localScopeState: input.localScopeState, | |
| 2901 | 2956 | }) |
| 2902 | 2957 | : isExecutorMcpSourceInput(sourceInput) |
| 2903 | 2958 | ? connectMcpSourceInternal({ |
| @@ -2905,8 +2960,8 @@ const createRuntimeSourceConnectionService = ( · 1 unmodified line | ||
| 2905 | 2960 | sourceStore: input.sourceStore, |
| 2906 | 2961 | sourceCatalogSync: input.sourceCatalogSync, |
| 2907 | 2962 | getLocalServerBaseUrl: input.getLocalServerBaseUrl, |
| 2908 | − workspaceId: sourceInput.workspaceId, | |
| 2909 | − actorAccountId: sourceInput.actorAccountId, | |
| 2963 | + scopeId: sourceInput.scopeId, | |
| 2964 | + actorScopeId: sourceInput.actorScopeId, | |
| 2910 | 2965 | executionId: sourceInput.executionId, |
| 2911 | 2966 | interactionId: sourceInput.interactionId, |
| 2912 | 2967 | endpoint: sourceInput.endpoint, |
| @@ -2936,6 +2991,7 @@ const createRuntimeSourceConnectionService = ( · 23 unmodified lines | ||
| 2936 | 2991 | sourceCatalogSync: input.sourceCatalogSync, |
| 2937 | 2992 | sourceInput, |
| 2938 | 2993 | getLocalServerBaseUrl: input.getLocalServerBaseUrl, |
| 2994 | + localScopeState: input.localScopeState, | |
| 2939 | 2995 | }), |
| 2940 | 2996 | ), |
| 2941 | 2997 | |
| @@ -2946,8 +3002,8 @@ const createRuntimeSourceConnectionService = ( · 4 unmodified lines | ||
| 2946 | 3002 | sourceStore: input.sourceStore, |
| 2947 | 3003 | sourceCatalogSync: input.sourceCatalogSync, |
| 2948 | 3004 | getLocalServerBaseUrl: input.getLocalServerBaseUrl, |
| 2949 | − workspaceId: sourceInput.workspaceId, | |
| 2950 | − actorAccountId: sourceInput.actorAccountId, | |
| 3005 | + scopeId: sourceInput.scopeId, | |
| 3006 | + actorScopeId: sourceInput.actorScopeId, | |
| 2951 | 3007 | sourceId: sourceInput.sourceId, |
| 2952 | 3008 | executionId: null, |
| 2953 | 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 | 3029 | provideLocalWorkspace( |
| 2974 | − input.executorState.workspaceOauthClients.listByWorkspaceAndProvider({ | |
| 2975 | − workspaceId, | |
| 2976 | − providerKey, | |
| 3030 | + Effect.gen(function* () { | |
| 3031 | + const scopeIds = resolvedScopeSearchOrder({ | |
| 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 | 3054 | provideLocalWorkspace( |
| 2982 | 3055 | Effect.gen(function* () { |
| 2983 | 3056 | const sourceAdapter = findSourceAdapterByProviderKey(providerKey); |
| 2984 | − const created = yield* createWorkspaceOauthClient({ | |
| 3057 | + const created = yield* createScopeOauthClient({ | |
| 2985 | 3058 | executorState: input.executorState, |
| 2986 | − workspaceId, | |
| 3059 | + scopeId, | |
| 2987 | 3060 | providerKey, |
| 2988 | 3061 | oauthClient, |
| 2989 | 3062 | label, |
| 2990 | 3063 | normalizeOauthClient: sourceAdapter?.normalizeOauthClientInput, |
| 2991 | 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 | 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 | 3071 | return stored.value; |
| 2999 | 3072 | }), |
| 3000 | 3073 | ), |
| 3001 | 3074 | |
| 3002 | − removeWorkspaceOauthClient: ({ workspaceId, oauthClientId }) => | |
| 3075 | + removeScopeOauthClient: ({ scopeId, oauthClientId }) => | |
| 3003 | 3076 | provideLocalWorkspace( |
| 3004 | 3077 | Effect.gen(function* () { |
| 3005 | − const oauthClient = yield* input.executorState.workspaceOauthClients.getById(oauthClientId); | |
| 3006 | − if (Option.isNone(oauthClient) || oauthClient.value.workspaceId !== workspaceId) { | |
| 3078 | + const oauthClient = yield* input.executorState.scopeOauthClients.getById(oauthClientId); | |
| 3079 | + if (Option.isNone(oauthClient) || oauthClient.value.scopeId !== scopeId) { | |
| 3007 | 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 | 3084 | const dependentGrant = grants.find((grant) => grant.oauthClientId === oauthClientId); |
| 3012 | 3085 | if (dependentGrant) { |
| 3013 | 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 | 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 | 3093 | if (removed && secretRef) { |
| 3021 | 3094 | yield* input.deleteSecretMaterial(secretRef).pipe( |
| 3022 | 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 | 3105 | provideLocalWorkspace( |
| 3033 | 3106 | removeProviderAuthGrantInternal({ |
| 3034 | 3107 | executorState: input.executorState, |
| 3035 | 3108 | sourceStore: input.sourceStore, |
| 3036 | − workspaceId, | |
| 3109 | + scopeId, | |
| 3037 | 3110 | grantId, |
| 3038 | 3111 | deleteSecretMaterial: input.deleteSecretMaterial, |
| 3039 | 3112 | }), |
| @@ -3043,7 +3116,7 @@ const createRuntimeSourceConnectionService = ( · 3 unmodified lines | ||
| 3043 | 3116 | |
| 3044 | 3117 | const createRuntimeSourceOAuthSessionService = ( |
| 3045 | 3118 | input: RuntimeSourceAuthDependencies, |
| 3046 | − provideLocalWorkspace: ProvideLocalWorkspace, | |
| 3119 | + provideLocalWorkspace: ProvideLocalScope, | |
| 3047 | 3120 | ): RuntimeSourceOAuthSessionServiceShape => ({ |
| 3048 | 3121 | startSourceOAuthSession: (oauthInput) => |
| 3049 | 3122 | Effect.gen(function* () { |
| @@ -3069,9 +3142,9 @@ const createRuntimeSourceOAuthSessionService = ( · 19 unmodified lines | ||
| 3069 | 3142 | |
| 3070 | 3143 | yield* input.executorState.sourceAuthSessions.upsert({ |
| 3071 | 3144 | id: sessionId, |
| 3072 | − workspaceId: oauthInput.workspaceId, | |
| 3145 | + scopeId: oauthInput.scopeId, | |
| 3073 | 3146 | sourceId: SourceIdSchema.make(`oauth_draft_${crypto.randomUUID()}`), |
| 3074 | − actorAccountId: oauthInput.actorAccountId ?? null, | |
| 3147 | + actorScopeId: oauthInput.actorScopeId ?? null, | |
| 3075 | 3148 | credentialSlot: "runtime", |
| 3076 | 3149 | executionId: null, |
| 3077 | 3150 | interactionId: null, |
| @@ -3215,7 +3288,7 @@ const createRuntimeSourceOAuthSessionService = ( · 137 unmodified lines | ||
| 3215 | 3288 | } satisfies CompleteSourceOAuthSessionResult; |
| 3216 | 3289 | })), |
| 3217 | 3290 | |
| 3218 | − completeProviderOauthCallback: ({ workspaceId, actorAccountId, state, code, error, errorDescription }) => | |
| 3291 | + completeProviderOauthCallback: ({ scopeId, actorScopeId, state, code, error, errorDescription }) => | |
| 3219 | 3292 | provideLocalWorkspace(Effect.gen(function* () { |
| 3220 | 3293 | const sessionOption = yield* input.executorState.sourceAuthSessions.getByState(state); |
| 3221 | 3294 | if (Option.isNone(sessionOption)) { |
| @@ -3223,10 +3296,10 @@ const createRuntimeSourceOAuthSessionService = ( · 1 unmodified line | ||
| 3223 | 3296 | } |
| 3224 | 3297 | |
| 3225 | 3298 | const session = sessionOption.value; |
| 3226 | − if (session.workspaceId !== workspaceId) { | |
| 3227 | − return yield* runtimeEffectError("sources/source-auth-service", `Source auth session ${session.id} does not match workspaceId=${workspaceId}`); | |
| 3299 | + if (session.scopeId !== scopeId) { | |
| 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 | 3303 | return yield* runtimeEffectError("sources/source-auth-service", `Source auth session ${session.id} does not match the active account`); |
| 3231 | 3304 | } |
| 3232 | 3305 | if (session.providerKind !== "oauth2_provider_batch") { |
| @@ -3238,9 +3311,9 @@ const createRuntimeSourceOAuthSessionService = ( · 5 unmodified lines | ||
| 3238 | 3311 | sessionData.targetSources, |
| 3239 | 3312 | (target) => |
| 3240 | 3313 | input.sourceStore.loadSourceById({ |
| 3241 | − workspaceId, | |
| 3314 | + scopeId, | |
| 3242 | 3315 | sourceId: target.sourceId, |
| 3243 | − actorAccountId, | |
| 3316 | + actorScopeId, | |
| 3244 | 3317 | }), |
| 3245 | 3318 | { discard: false }, |
| 3246 | 3319 | ); |
| @@ -3276,14 +3349,15 @@ const createRuntimeSourceOAuthSessionService = ( · 29 unmodified lines | ||
| 3276 | 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 | 3353 | executorState: input.executorState, |
| 3281 | − workspaceId, | |
| 3354 | + scopeId, | |
| 3282 | 3355 | oauthClientId: sessionData.oauthClientId, |
| 3283 | 3356 | providerKey: sessionData.providerKey, |
| 3357 | + localScopeState: input.localScopeState, | |
| 3284 | 3358 | }); |
| 3285 | 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 | 3363 | let clientSecret: string | null = null; |
| @@ -3303,9 +3377,9 @@ const createRuntimeSourceOAuthSessionService = ( · 13 unmodified lines | ||
| 3303 | 3377 | code: authorizationCode, |
| 3304 | 3378 | }); |
| 3305 | 3379 | |
| 3306 | − const availableGrants = yield* input.executorState.providerAuthGrants.listByWorkspaceActorAndProvider({ | |
| 3307 | − workspaceId, | |
| 3308 | − actorAccountId: actorAccountId ?? null, | |
| 3380 | + const availableGrants = yield* input.executorState.providerAuthGrants.listByScopeActorAndProvider({ | |
| 3381 | + scopeId, | |
| 3382 | + actorScopeId: actorScopeId ?? null, | |
| 3309 | 3383 | providerKey: sessionData.providerKey, |
| 3310 | 3384 | }); |
| 3311 | 3385 | const existingGrant = availableGrants.find( |
| @@ -3319,8 +3393,8 @@ const createRuntimeSourceOAuthSessionService = ( · 7 unmodified lines | ||
| 3319 | 3393 | ); |
| 3320 | 3394 | const nextGrant = yield* upsertProviderAuthGrant({ |
| 3321 | 3395 | executorState: input.executorState, |
| 3322 | − workspaceId, | |
| 3323 | − actorAccountId, | |
| 3396 | + scopeId, | |
| 3397 | + actorScopeId, | |
| 3324 | 3398 | providerKey: sessionData.providerKey, |
| 3325 | 3399 | oauthClientId: sessionData.oauthClientId, |
| 3326 | 3400 | tokenEndpoint: sessionData.tokenEndpoint, |
| @@ -3339,9 +3413,9 @@ const createRuntimeSourceOAuthSessionService = ( · 12 unmodified lines | ||
| 3339 | 3413 | (target) => |
| 3340 | 3414 | Effect.map( |
| 3341 | 3415 | input.sourceStore.loadSourceById({ |
| 3342 | − workspaceId, | |
| 3416 | + scopeId, | |
| 3343 | 3417 | sourceId: target.sourceId, |
| 3344 | − actorAccountId, | |
| 3418 | + actorScopeId, | |
| 3345 | 3419 | }), |
| 3346 | 3420 | (source) => ({ |
| 3347 | 3421 | source, |
| @@ -3354,7 +3428,7 @@ const createRuntimeSourceOAuthSessionService = ( · 6 unmodified lines | ||
| 3354 | 3428 | const connectedSources = yield* attachProviderGrantToSources({ |
| 3355 | 3429 | sourceStore: input.sourceStore, |
| 3356 | 3430 | sourceCatalogSync: input.sourceCatalogSync, |
| 3357 | − actorAccountId, | |
| 3431 | + actorScopeId, | |
| 3358 | 3432 | grantId: nextGrant.id, |
| 3359 | 3433 | providerKey: nextGrant.providerKey, |
| 3360 | 3434 | headerName: nextGrant.headerName, |
| @@ -3384,7 +3458,7 @@ const createRuntimeSourceOAuthSessionService = ( · 23 unmodified lines | ||
| 3384 | 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 | 3462 | provideLocalWorkspace(Effect.gen(function* () { |
| 3389 | 3463 | const sessionOption = yield* input.executorState.sourceAuthSessions.getByState(state); |
| 3390 | 3464 | if (Option.isNone(sessionOption)) { |
| @@ -3392,22 +3466,22 @@ const createRuntimeSourceOAuthSessionService = ( · 1 unmodified line | ||
| 3392 | 3466 | } |
| 3393 | 3467 | |
| 3394 | 3468 | const session = sessionOption.value; |
| 3395 | − if (session.workspaceId !== workspaceId || session.sourceId !== sourceId) { | |
| 3469 | + if (session.scopeId !== scopeId || session.sourceId !== sourceId) { | |
| 3396 | 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 | 3474 | if ( |
| 3401 | − actorAccountId !== undefined | |
| 3402 | − && (session.actorAccountId ?? null) !== (actorAccountId ?? null) | |
| 3475 | + actorScopeId !== undefined | |
| 3476 | + && (session.actorScopeId ?? null) !== (actorScopeId ?? null) | |
| 3403 | 3477 | ) { |
| 3404 | 3478 | return yield* runtimeEffectError("sources/source-auth-service", `Source auth session ${session.id} does not match the active account`); |
| 3405 | 3479 | } |
| 3406 | 3480 | |
| 3407 | 3481 | const source = yield* input.sourceStore.loadSourceById({ |
| 3408 | − workspaceId: session.workspaceId, | |
| 3482 | + scopeId: session.scopeId, | |
| 3409 | 3483 | sourceId: session.sourceId, |
| 3410 | − actorAccountId: session.actorAccountId, | |
| 3484 | + actorScopeId: session.actorScopeId, | |
| 3411 | 3485 | }); |
| 3412 | 3486 | |
| 3413 | 3487 | if (session.status === "completed") { |
| @@ -3439,13 +3513,13 @@ const createRuntimeSourceOAuthSessionService = ( · 25 unmodified lines | ||
| 3439 | 3513 | }), |
| 3440 | 3514 | ); |
| 3441 | 3515 | const failedSource = yield* updateSourceStatus(input.sourceStore, source, { |
| 3442 | − actorAccountId: session.actorAccountId, | |
| 3516 | + actorScopeId: session.actorScopeId, | |
| 3443 | 3517 | status: "error", |
| 3444 | 3518 | lastError: reason, |
| 3445 | 3519 | }); |
| 3446 | 3520 | yield* input.sourceCatalogSync.sync({ |
| 3447 | 3521 | source: failedSource, |
| 3448 | − actorAccountId: session.actorAccountId, | |
| 3522 | + actorScopeId: session.actorScopeId, | |
| 3449 | 3523 | }); |
| 3450 | 3524 | yield* completeLiveInteraction({ |
| 3451 | 3525 | executorState: input.executorState, |
| @@ -3503,7 +3577,7 @@ const createRuntimeSourceOAuthSessionService = ( · 51 unmodified lines | ||
| 3503 | 3577 | ? exchanged.scope!.split(/\s+/).filter((scope) => scope.length > 0) |
| 3504 | 3578 | : [...oauthSessionData.scopes]; |
| 3505 | 3579 | connectedSource = yield* updateSourceStatus(input.sourceStore, source, { |
| 3506 | − actorAccountId: session.actorAccountId, | |
| 3580 | + actorScopeId: session.actorScopeId, | |
| 3507 | 3581 | status: "connected", |
| 3508 | 3582 | lastError: null, |
| 3509 | 3583 | auth: { |
| @@ -3518,10 +3592,10 @@ const createRuntimeSourceOAuthSessionService = ( · 8 unmodified lines | ||
| 3518 | 3592 | grantSet: grantedScopes, |
| 3519 | 3593 | }, |
| 3520 | 3594 | }); |
| 3521 | − const authArtifact = yield* input.executorState.authArtifacts.getByWorkspaceSourceAndActor({ | |
| 3522 | − workspaceId: connectedSource.workspaceId, | |
| 3595 | + const authArtifact = yield* input.executorState.authArtifacts.getByScopeSourceAndActor({ | |
| 3596 | + scopeId: connectedSource.scopeId, | |
| 3523 | 3597 | sourceId: connectedSource.id, |
| 3524 | − actorAccountId: session.actorAccountId ?? null, | |
| 3598 | + actorScopeId: session.actorScopeId ?? null, | |
| 3525 | 3599 | slot: "runtime", |
| 3526 | 3600 | }); |
| 3527 | 3601 | if (Option.isSome(authArtifact)) { |
| @@ -3583,7 +3657,7 @@ const createRuntimeSourceOAuthSessionService = ( · 55 unmodified lines | ||
| 3583 | 3657 | : null; |
| 3584 | 3658 | |
| 3585 | 3659 | connectedSource = yield* updateSourceStatus(input.sourceStore, source, { |
| 3586 | − actorAccountId: session.actorAccountId, | |
| 3660 | + actorScopeId: session.actorScopeId, | |
| 3587 | 3661 | status: "connected", |
| 3588 | 3662 | lastError: null, |
| 3589 | 3663 | auth: createPersistedMcpOAuthSourceAuth({ |
| @@ -3628,13 +3702,13 @@ const createRuntimeSourceOAuthSessionService = ( · 38 unmodified lines | ||
| 3628 | 3702 | const indexed = yield* Effect.either( |
| 3629 | 3703 | input.sourceCatalogSync.sync({ |
| 3630 | 3704 | source: connectedSource, |
| 3631 | − actorAccountId: session.actorAccountId, | |
| 3705 | + actorScopeId: session.actorScopeId, | |
| 3632 | 3706 | }), |
| 3633 | 3707 | ); |
| 3634 | 3708 | yield* Either.match(indexed, { |
| 3635 | 3709 | onLeft: (error) => |
| 3636 | 3710 | updateSourceStatus(input.sourceStore, connectedSource, { |
| 3637 | − actorAccountId: session.actorAccountId, | |
| 3711 | + actorScopeId: session.actorScopeId, | |
| 3638 | 3712 | status: "error", |
| 3639 | 3713 | lastError: error.message, |
| 3640 | 3714 | }).pipe( |
| @@ -3660,8 +3734,8 @@ const createRuntimeSourceOAuthSessionService = ( · 19 unmodified lines | ||
| 3660 | 3734 | }); |
| 3661 | 3735 | |
| 3662 | 3736 | export const createRuntimeSourceAuthService = (input: RuntimeSourceAuthDependencies) => { |
| 3663 | − const provideLocalWorkspace: ProvideLocalWorkspace = (effect) => | |
| 3664 | − provideOptionalRuntimeLocalWorkspace(effect, input.localWorkspaceState); | |
| 3737 | + const provideLocalWorkspace: ProvideLocalScope = (effect) => | |
| 3738 | + provideOptionalRuntimeLocalScope(effect, input.localScopeState); | |
| 3665 | 3739 | const sourceConnection = createRuntimeSourceConnectionService( |
| 3666 | 3740 | input, |
| 3667 | 3741 | provideLocalWorkspace, |
| @@ -3704,7 +3778,7 @@ export const RuntimeSourceAuthServiceLive = (input: { · 36 unmodified lines | ||
| 3704 | 3778 | const resolveSecretMaterial = yield* SecretMaterialResolverService; |
| 3705 | 3779 | const storeSecretMaterial = yield* SecretMaterialStorerService; |
| 3706 | 3780 | const deleteSecretMaterial = yield* SecretMaterialDeleterService; |
| 3707 | − const runtimeLocalWorkspace = yield* getRuntimeLocalWorkspaceOption(); | |
| 3781 | + const runtimeLocalScope = yield* getRuntimeLocalScopeOption(); | |
| 3708 | 3782 | |
| 3709 | 3783 | return createRuntimeSourceAuthService({ |
| 3710 | 3784 | executorState, |
| @@ -3715,7 +3789,7 @@ export const RuntimeSourceAuthServiceLive = (input: { · 4 unmodified lines | ||
| 3715 | 3789 | storeSecretMaterial, |
| 3716 | 3790 | deleteSecretMaterial, |
| 3717 | 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 | 5 | import * as Schema from "effect/Schema"; |
| 3 | 6 | |
| 4 | 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 | 6 | import * as Effect from "effect/Effect"; |
| 3 | 7 | |
| 4 | 8 | import { |
| 5 | 9 | CredentialIdSchema, |
| 6 | 10 | decodeBuiltInAuthArtifactConfig, |
| 7 | 11 | SourceIdSchema, |
| 8 | − WorkspaceIdSchema, | |
| 12 | + ScopeIdSchema, | |
| 9 | 13 | type Source, |
| 10 | 14 | } from "#schema"; |
| 11 | 15 | |
| @@ -17,7 +21,9 @@ import { · 5 unmodified lines | ||
| 17 | 21 | stableSourceCatalogRevisionId, |
| 18 | 22 | updateSourceFromPayload, |
| 19 | 23 | } from "./source-definitions"; |
| 20 | −import { namespaceFromSourceName } from "./source-names"; | |
| 24 | +import { | |
| 25 | + namespaceFromSourceName, | |
| 26 | +} from "./source-names"; | |
| 21 | 27 | |
| 22 | 28 | const openApiBinding = ( |
| 23 | 29 | specUrl = "https://api.github.com/openapi.json", |
| @@ -81,7 +87,7 @@ const mcpBinding = ( · 57 unmodified lines | ||
| 81 | 87 | |
| 82 | 88 | const makeSource = (overrides: Partial<Source> = {}): Source => ({ |
| 83 | 89 | id: SourceIdSchema.make("src_source_definitions"), |
| 84 | − workspaceId: WorkspaceIdSchema.make("ws_source_definitions"), | |
| 90 | + scopeId: ScopeIdSchema.make("ws_source_definitions"), | |
| 85 | 91 | name: "GitHub", |
| 86 | 92 | kind: "openapi", |
| 87 | 93 | endpoint: "https://api.github.com", |
| @@ -108,7 +114,7 @@ describe("source-definitions", () => { · 20 unmodified lines | ||
| 108 | 114 | name: "Renamed GitHub", |
| 109 | 115 | }); |
| 110 | 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 | 120 | expect(stableSourceCatalogId(source)).toBe(stableSourceCatalogId(source)); |
| @@ -151,7 +157,7 @@ describe("source-definitions", () => { · 36 unmodified lines | ||
| 151 | 157 | () => |
| 152 | 158 | Effect.gen(function* () { |
| 153 | 159 | const source = yield* createSourceFromPayload({ |
| 154 | − workspaceId: WorkspaceIdSchema.make("ws_create_defaults"), | |
| 160 | + scopeId: ScopeIdSchema.make("ws_create_defaults"), | |
| 155 | 161 | sourceId: SourceIdSchema.make("src_create_defaults"), |
| 156 | 162 | payload: { |
| 157 | 163 | name: " GitHub ", |
| @@ -216,7 +222,7 @@ describe("source-definitions", () => { · 58 unmodified lines | ||
| 216 | 222 | () => |
| 217 | 223 | Effect.gen(function* () { |
| 218 | 224 | const source = yield* createSourceFromPayload({ |
| 219 | − workspaceId: WorkspaceIdSchema.make("ws_create_oauth_defaults"), | |
| 225 | + scopeId: ScopeIdSchema.make("ws_create_oauth_defaults"), | |
| 220 | 226 | sourceId: SourceIdSchema.make("src_create_oauth_defaults"), |
| 221 | 227 | payload: { |
| 222 | 228 | name: "GraphQL Demo", |
| @@ -253,7 +259,7 @@ describe("source-definitions", () => { · 30 unmodified lines | ||
| 253 | 259 | Effect.gen(function* () { |
| 254 | 260 | const invalidBearer = yield* Effect.flip( |
| 255 | 261 | createSourceFromPayload({ |
| 256 | − workspaceId: WorkspaceIdSchema.make("ws_invalid_bearer"), | |
| 262 | + scopeId: ScopeIdSchema.make("ws_invalid_bearer"), | |
| 257 | 263 | sourceId: SourceIdSchema.make("src_invalid_bearer"), |
| 258 | 264 | payload: { |
| 259 | 265 | name: "Bad Bearer", |
| @@ -279,7 +285,7 @@ describe("source-definitions", () => { · 19 unmodified lines | ||
| 279 | 285 | |
| 280 | 286 | const invalidRefresh = yield* Effect.flip( |
| 281 | 287 | createSourceFromPayload({ |
| 282 | − workspaceId: WorkspaceIdSchema.make("ws_invalid_refresh"), | |
| 288 | + scopeId: ScopeIdSchema.make("ws_invalid_refresh"), | |
| 283 | 289 | sourceId: SourceIdSchema.make("src_invalid_refresh"), |
| 284 | 290 | payload: { |
| 285 | 291 | name: "Bad OAuth", |
| @@ -313,7 +319,7 @@ describe("source-definitions", () => { · 27 unmodified lines | ||
| 313 | 319 | Effect.gen(function* () { |
| 314 | 320 | const invalidMcp = yield* Effect.flip( |
| 315 | 321 | createSourceFromPayload({ |
| 316 | − workspaceId: WorkspaceIdSchema.make("ws_invalid_mcp"), | |
| 322 | + scopeId: ScopeIdSchema.make("ws_invalid_mcp"), | |
| 317 | 323 | sourceId: SourceIdSchema.make("src_invalid_mcp"), |
| 318 | 324 | payload: { |
| 319 | 325 | name: "MCP", |
| @@ -332,7 +338,7 @@ describe("source-definitions", () => { · 12 unmodified lines | ||
| 332 | 338 | |
| 333 | 339 | const invalidOpenApiSpec = yield* Effect.flip( |
| 334 | 340 | createSourceFromPayload({ |
| 335 | − workspaceId: WorkspaceIdSchema.make("ws_invalid_openapi_spec"), | |
| 341 | + scopeId: ScopeIdSchema.make("ws_invalid_openapi_spec"), | |
| 336 | 342 | sourceId: SourceIdSchema.make("src_invalid_openapi_spec"), |
| 337 | 343 | payload: { |
| 338 | 344 | name: "OpenAPI", |
| @@ -349,7 +355,7 @@ describe("source-definitions", () => { · 10 unmodified lines | ||
| 349 | 355 | |
| 350 | 356 | const invalidOpenApiTransport = yield* Effect.flip( |
| 351 | 357 | createSourceFromPayload({ |
| 352 | − workspaceId: WorkspaceIdSchema.make("ws_invalid_openapi_transport"), | |
| 358 | + scopeId: ScopeIdSchema.make("ws_invalid_openapi_transport"), | |
| 353 | 359 | sourceId: SourceIdSchema.make("src_invalid_openapi_transport"), |
| 354 | 360 | payload: { |
| 355 | 361 | name: "OpenAPI", |
| @@ -369,7 +375,7 @@ describe("source-definitions", () => { · 13 unmodified lines | ||
| 369 | 375 | |
| 370 | 376 | const invalidGraphql = yield* Effect.flip( |
| 371 | 377 | createSourceFromPayload({ |
| 372 | − workspaceId: WorkspaceIdSchema.make("ws_invalid_graphql"), | |
| 378 | + scopeId: ScopeIdSchema.make("ws_invalid_graphql"), | |
| 373 | 379 | sourceId: SourceIdSchema.make("src_invalid_graphql"), |
| 374 | 380 | payload: { |
| 375 | 381 | name: "GraphQL", |
| @@ -388,7 +394,7 @@ describe("source-definitions", () => { · 12 unmodified lines | ||
| 388 | 394 | |
| 389 | 395 | const invalidInternal = yield* Effect.flip( |
| 390 | 396 | createSourceFromPayload({ |
| 391 | − workspaceId: WorkspaceIdSchema.make("ws_invalid_internal"), | |
| 397 | + scopeId: ScopeIdSchema.make("ws_invalid_internal"), | |
| 392 | 398 | sourceId: SourceIdSchema.make("src_invalid_internal"), |
| 393 | 399 | payload: { |
| 394 | 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 | 5 | import type { |
| 4 | 6 | CreateSourcePayload, |
| 5 | 7 | UpdateSourcePayload, |
| 6 | 8 | } from "../../sources/contracts"; |
| 7 | 9 | import type { |
| 8 | − AccountId, | |
| 10 | + ScopeId, | |
| 9 | 11 | AuthArtifact, |
| 10 | 12 | Source, |
| 11 | 13 | SourceAuth, |
| @@ -17,7 +19,6 @@ import type { · 5 unmodified lines | ||
| 17 | 19 | StoredSourceRecord, |
| 18 | 20 | StoredSourceCatalogRecord, |
| 19 | 21 | StoredSourceCatalogRevisionRecord, |
| 20 | − WorkspaceId, | |
| 21 | 22 | } from "#schema"; |
| 22 | 23 | import { |
| 23 | 24 | AuthArtifactIdSchema, |
| @@ -27,12 +28,17 @@ import { · 3 unmodified lines | ||
| 27 | 28 | } from "#schema"; |
| 28 | 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 | 35 | import { |
| 32 | 36 | authArtifactFromSourceAuth, |
| 33 | 37 | sourceAuthFromAuthArtifact, |
| 34 | 38 | } from "../auth/auth-artifacts"; |
| 35 | −import { runtimeEffectError } from "../effect-errors"; | |
| 39 | +import { | |
| 40 | + runtimeEffectError, | |
| 41 | +} from "../effect-errors"; | |
| 36 | 42 | |
| 37 | 43 | const trimOrNull = (value: string | null | undefined): string | null => { |
| 38 | 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 | 285 | export const createSourceFromPayload = (input: { |
| 280 | − workspaceId: WorkspaceId; | |
| 286 | + scopeId: ScopeId; | |
| 281 | 287 | sourceId: Source["id"]; |
| 282 | 288 | payload: CreateSourcePayload; |
| 283 | 289 | now: number; |
| @@ -292,7 +298,7 @@ export const createSourceFromPayload = (input: { · 8 unmodified lines | ||
| 292 | 298 | |
| 293 | 299 | return yield* validateSourceByKind({ |
| 294 | 300 | id: input.sourceId, |
| 295 | − workspaceId: input.workspaceId, | |
| 301 | + scopeId: input.scopeId, | |
| 296 | 302 | name: input.payload.name.trim(), |
| 297 | 303 | kind: input.payload.kind, |
| 298 | 304 | endpoint: input.payload.endpoint.trim(), |
| @@ -370,7 +376,7 @@ export const createSourceCatalogRecord = (input: { · 71 unmodified lines | ||
| 370 | 376 | providerKey: sourceCatalogProviderKeyFromSource(input.source), |
| 371 | 377 | name: input.source.name, |
| 372 | 378 | summary: null, |
| 373 | − visibility: "workspace", | |
| 379 | + visibility: "scope", | |
| 374 | 380 | latestRevisionId: input.latestRevisionId, |
| 375 | 381 | createdAt: input.source.createdAt, |
| 376 | 382 | updatedAt: input.source.updatedAt, |
| @@ -402,7 +408,7 @@ export const splitSourceForStorage = (input: { · 25 unmodified lines | ||
| 402 | 408 | source: Source; |
| 403 | 409 | catalogId: SourceCatalogId; |
| 404 | 410 | catalogRevisionId: SourceCatalogRevisionId; |
| 405 | − actorAccountId?: AccountId | null; | |
| 411 | + actorScopeId?: ScopeId | null; | |
| 406 | 412 | existingRuntimeAuthArtifactId?: AuthArtifact["id"] | null; |
| 407 | 413 | existingImportAuthArtifactId?: AuthArtifact["id"] | null; |
| 408 | 414 | }): { |
| @@ -412,7 +418,7 @@ export const splitSourceForStorage = (input: { · 3 unmodified lines | ||
| 412 | 418 | } => { |
| 413 | 419 | const sourceRecord: StoredSourceRecord = { |
| 414 | 420 | id: input.source.id, |
| 415 | − workspaceId: input.source.workspaceId, | |
| 421 | + scopeId: input.source.scopeId, | |
| 416 | 422 | catalogId: input.catalogId, |
| 417 | 423 | catalogRevisionId: input.catalogRevisionId, |
| 418 | 424 | name: input.source.name, |
| @@ -435,7 +441,7 @@ export const splitSourceForStorage = (input: { · 16 unmodified lines | ||
| 435 | 441 | source: input.source, |
| 436 | 442 | auth: input.source.auth, |
| 437 | 443 | slot: "runtime", |
| 438 | − actorAccountId: input.actorAccountId, | |
| 444 | + actorScopeId: input.actorScopeId, | |
| 439 | 445 | existingAuthArtifactId: input.existingRuntimeAuthArtifactId |
| 440 | 446 | ?? AuthArtifactIdSchema.make(`auth_art_${crypto.randomUUID()}`), |
| 441 | 447 | }), |
| @@ -444,7 +450,7 @@ export const splitSourceForStorage = (input: { · 2 unmodified lines | ||
| 444 | 450 | source: input.source, |
| 445 | 451 | auth: input.source.importAuth, |
| 446 | 452 | slot: "import", |
| 447 | − actorAccountId: input.actorAccountId, | |
| 453 | + actorScopeId: input.actorScopeId, | |
| 448 | 454 | existingAuthArtifactId: input.existingImportAuthArtifactId |
| 449 | 455 | ?? AuthArtifactIdSchema.make(`auth_art_${crypto.randomUUID()}`), |
| 450 | 456 | }) |
| @@ -466,7 +472,7 @@ export const projectSourceFromStorage = (input: { · 15 unmodified lines | ||
| 466 | 472 | |
| 467 | 473 | return { |
| 468 | 474 | id: input.sourceRecord.id, |
| 469 | − workspaceId: input.sourceRecord.workspaceId, | |
| 475 | + scopeId: input.sourceRecord.scopeId, | |
| 470 | 476 | name: input.sourceRecord.name, |
| 471 | 477 | kind: input.sourceRecord.kind, |
| 472 | 478 | endpoint: input.sourceRecord.endpoint, |
| @@ -507,7 +513,7 @@ export const projectSourcesFromStorage = (input: { · 34 unmodified lines | ||
| 507 | 513 | import: null, |
| 508 | 514 | }; |
| 509 | 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 | 517 | authArtifactsBySourceId.set(authArtifact.sourceId, { |
| 512 | 518 | ...existing, |
| 513 | 519 | [authArtifact.slot]: authArtifact, |
| @@ -4,10 +4,16 @@ import { · 3 unmodified lines | ||
| 4 | 4 | type ServerResponse, |
| 5 | 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 | 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 | 18 | type TestServer = { |
| 13 | 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 | 6 | import * as Effect from "effect/Effect"; |
| 3 | 7 | |
| 4 | −import type { LoadedSourceCatalogTool } from "../catalog/source/runtime"; | |
| 5 | −import { inspectionToolDetailFromTool } from "./source-inspection"; | |
| 8 | +import type { | |
| 9 | + LoadedSourceCatalogTool, | |
| 10 | +} from "../catalog/source/runtime"; | |
| 11 | +import { | |
| 12 | + inspectionToolDetailFromTool, | |
| 13 | +} from "./source-inspection"; | |
| 6 | 14 | |
| 7 | 15 | describe("source inspection", () => { |
| 8 | 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 | 6 | import * as Effect from "effect/Effect"; |
| 3 | 7 | |
| 4 | 8 | import { |
| 5 | 9 | SourceIdSchema, |
| 6 | − WorkspaceIdSchema, | |
| 10 | + ScopeIdSchema, | |
| 7 | 11 | type Source, |
| 8 | 12 | } from "#schema"; |
| 9 | 13 | |
| 10 | −import type { LoadedLocalExecutorConfig } from "../workspace-config"; | |
| 11 | −import { buildLocalSourceRecord } from "./source-store"; | |
| 12 | −import type { LocalWorkspaceState } from "../workspace-state"; | |
| 14 | +import type { | |
| 15 | + LoadedLocalExecutorConfig, | |
| 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 | 25 | const sourceId = SourceIdSchema.make("linear"); |
| 16 | 26 | |
| 17 | 27 | const loadedConfig: LoadedLocalExecutorConfig = { |
| @@ -36,7 +46,7 @@ const loadedConfig: LoadedLocalExecutorConfig = { · 18 unmodified lines | ||
| 36 | 46 | projectConfigPath: "/tmp/project-config.jsonc", |
| 37 | 47 | }; |
| 38 | 48 | |
| 39 | −const workspaceState: LocalWorkspaceState = { | |
| 49 | +const scopeState: LocalScopeState = { | |
| 40 | 50 | version: 1, |
| 41 | 51 | sources: { |
| 42 | 52 | [sourceId]: { |
| @@ -54,16 +64,16 @@ describe("source-store", () => { · 11 unmodified lines | ||
| 54 | 64 | it.effect("projects configured sources without reading local artifacts", () => |
| 55 | 65 | Effect.gen(function* () { |
| 56 | 66 | const result = yield* buildLocalSourceRecord({ |
| 57 | − workspaceId, | |
| 67 | + scopeId, | |
| 58 | 68 | loadedConfig, |
| 59 | − workspaceState, | |
| 69 | + scopeState, | |
| 60 | 70 | sourceId, |
| 61 | 71 | authArtifacts: [], |
| 62 | 72 | }); |
| 63 | 73 | |
| 64 | 74 | expect(result.source).toEqual({ |
| 65 | 75 | id: sourceId, |
| 66 | − workspaceId, | |
| 76 | + scopeId, | |
| 67 | 77 | name: "Linear GraphQL", |
| 68 | 78 | kind: "graphql", |
| 69 | 79 | endpoint: "https://api.linear.app/graphql", |
| @@ -1,22 +1,30 @@ | ||
| 1 | 1 | import type { |
| 2 | − AccountId, | |
| 2 | + ScopeId, | |
| 3 | 3 | Source, |
| 4 | − WorkspaceId, | |
| 5 | 4 | } from "#schema"; |
| 6 | 5 | import * as Context from "effect/Context"; |
| 7 | 6 | import * as Effect from "effect/Effect"; |
| 8 | 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 | 12 | import { |
| 12 | 13 | SourceArtifactStore, |
| 13 | − type WorkspaceStorageServices, | |
| 14 | − WorkspaceConfigStore, | |
| 15 | − WorkspaceStateStore, | |
| 16 | −} from "../workspace/storage"; | |
| 17 | −import { SecretMaterialDeleterService } from "../workspace/secret-material-providers"; | |
| 18 | −import { RuntimeLocalWorkspaceService } from "../workspace/runtime-context"; | |
| 19 | −import { ExecutorStateStore, type ExecutorStateStoreShape } from "../executor-state-store"; | |
| 14 | + type ScopeStorageServices, | |
| 15 | + ScopeConfigStore, | |
| 16 | + ScopeStateStore, | |
| 17 | +} from "../scope/storage"; | |
| 18 | +import { | |
| 19 | + SecretMaterialDeleterService, | |
| 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 | 28 | import { |
| 21 | 29 | loadRuntimeSourceStoreDeps, |
| 22 | 30 | type RuntimeSourceStoreDeps, |
| @@ -35,95 +43,95 @@ import { · 12 unmodified lines | ||
| 35 | 43 | export { buildLocalSourceRecord } from "./source-store/records"; |
| 36 | 44 | |
| 37 | 45 | type RuntimeSourceStoreShape = { |
| 38 | − loadSourcesInWorkspace: ( | |
| 39 | − workspaceId: WorkspaceId, | |
| 40 | − options?: { actorAccountId?: AccountId | null }, | |
| 46 | + loadSourcesInScope: ( | |
| 47 | + scopeId: ScopeId, | |
| 48 | + options?: { actorScopeId?: ScopeId | null }, | |
| 41 | 49 | ) => ReturnType<typeof loadSourcesInWorkspaceWithDeps>; |
| 42 | − listLinkedSecretSourcesInWorkspace: ( | |
| 43 | − workspaceId: WorkspaceId, | |
| 44 | − options?: { actorAccountId?: AccountId | null }, | |
| 50 | + listLinkedSecretSourcesInScope: ( | |
| 51 | + scopeId: ScopeId, | |
| 52 | + options?: { actorScopeId?: ScopeId | null }, | |
| 45 | 53 | ) => ReturnType<typeof listLinkedSecretSourcesInWorkspaceWithDeps>; |
| 46 | 54 | loadSourceById: (input: { |
| 47 | − workspaceId: WorkspaceId; | |
| 55 | + scopeId: ScopeId; | |
| 48 | 56 | sourceId: Source["id"]; |
| 49 | − actorAccountId?: AccountId | null; | |
| 57 | + actorScopeId?: ScopeId | null; | |
| 50 | 58 | }) => ReturnType<typeof loadSourceByIdWithDeps>; |
| 51 | 59 | removeSourceById: (input: { |
| 52 | − workspaceId: WorkspaceId; | |
| 60 | + scopeId: ScopeId; | |
| 53 | 61 | sourceId: Source["id"]; |
| 54 | 62 | }) => ReturnType<typeof removeSourceByIdWithDeps>; |
| 55 | 63 | persistSource: ( |
| 56 | 64 | source: Source, |
| 57 | − options?: { actorAccountId?: AccountId | null }, | |
| 65 | + options?: { actorScopeId?: ScopeId | null }, | |
| 58 | 66 | ) => ReturnType<typeof persistSourceWithDeps>; |
| 59 | 67 | }; |
| 60 | 68 | |
| 61 | 69 | export type RuntimeSourceStore = RuntimeSourceStoreShape; |
| 62 | 70 | |
| 63 | −export const loadSourcesInWorkspace = ( | |
| 71 | +export const loadSourcesInScope = ( | |
| 64 | 72 | executorState: ExecutorStateStoreShape, |
| 65 | − workspaceId: WorkspaceId, | |
| 73 | + scopeId: ScopeId, | |
| 66 | 74 | options: { |
| 67 | − actorAccountId?: AccountId | null; | |
| 75 | + actorScopeId?: ScopeId | null; | |
| 68 | 76 | } = {}, |
| 69 | 77 | ): Effect.Effect< |
| 70 | 78 | readonly Source[], |
| 71 | 79 | Error, |
| 72 | − WorkspaceStorageServices | SourceTypeDeclarationsRefresherService | |
| 80 | + ScopeStorageServices | SourceTypeDeclarationsRefresherService | |
| 73 | 81 | > => |
| 74 | 82 | Effect.flatMap( |
| 75 | − loadRuntimeSourceStoreDeps(executorState, workspaceId), | |
| 76 | − (deps) => loadSourcesInWorkspaceWithDeps(deps, workspaceId, options), | |
| 83 | + loadRuntimeSourceStoreDeps(executorState, scopeId), | |
| 84 | + (deps) => loadSourcesInWorkspaceWithDeps(deps, scopeId, options), | |
| 77 | 85 | ); |
| 78 | 86 | |
| 79 | −export const listLinkedSecretSourcesInWorkspace = ( | |
| 87 | +export const listLinkedSecretSourcesInScope = ( | |
| 80 | 88 | executorState: ExecutorStateStoreShape, |
| 81 | − workspaceId: WorkspaceId, | |
| 89 | + scopeId: ScopeId, | |
| 82 | 90 | options: { |
| 83 | − actorAccountId?: AccountId | null; | |
| 91 | + actorScopeId?: ScopeId | null; | |
| 84 | 92 | } = {}, |
| 85 | 93 | ): Effect.Effect< |
| 86 | 94 | Map<string, Array<{ sourceId: string; sourceName: string }>>, |
| 87 | 95 | Error, |
| 88 | − WorkspaceStorageServices | SourceTypeDeclarationsRefresherService | |
| 96 | + ScopeStorageServices | SourceTypeDeclarationsRefresherService | |
| 89 | 97 | > => |
| 90 | 98 | Effect.flatMap( |
| 91 | − loadRuntimeSourceStoreDeps(executorState, workspaceId), | |
| 92 | − (deps) => listLinkedSecretSourcesInWorkspaceWithDeps(deps, workspaceId, options), | |
| 99 | + loadRuntimeSourceStoreDeps(executorState, scopeId), | |
| 100 | + (deps) => listLinkedSecretSourcesInWorkspaceWithDeps(deps, scopeId, options), | |
| 93 | 101 | ); |
| 94 | 102 | |
| 95 | 103 | export const loadSourceById = ( |
| 96 | 104 | executorState: ExecutorStateStoreShape, |
| 97 | 105 | input: { |
| 98 | − workspaceId: WorkspaceId; | |
| 106 | + scopeId: ScopeId; | |
| 99 | 107 | sourceId: Source["id"]; |
| 100 | − actorAccountId?: AccountId | null; | |
| 108 | + actorScopeId?: ScopeId | null; | |
| 101 | 109 | }, |
| 102 | 110 | ): Effect.Effect< |
| 103 | 111 | Source, |
| 104 | 112 | Error, |
| 105 | − WorkspaceStorageServices | SourceTypeDeclarationsRefresherService | |
| 113 | + ScopeStorageServices | SourceTypeDeclarationsRefresherService | |
| 106 | 114 | > => |
| 107 | 115 | Effect.flatMap( |
| 108 | − loadRuntimeSourceStoreDeps(executorState, input.workspaceId), | |
| 116 | + loadRuntimeSourceStoreDeps(executorState, input.scopeId), | |
| 109 | 117 | (deps) => loadSourceByIdWithDeps(deps, input), |
| 110 | 118 | ); |
| 111 | 119 | |
| 112 | 120 | export const removeSourceById = ( |
| 113 | 121 | executorState: ExecutorStateStoreShape, |
| 114 | 122 | input: { |
| 115 | − workspaceId: WorkspaceId; | |
| 123 | + scopeId: ScopeId; | |
| 116 | 124 | sourceId: Source["id"]; |
| 117 | 125 | }, |
| 118 | 126 | ): Effect.Effect< |
| 119 | 127 | boolean, |
| 120 | 128 | Error, |
| 121 | − | WorkspaceStorageServices | |
| 129 | + | ScopeStorageServices | |
| 122 | 130 | | SourceTypeDeclarationsRefresherService |
| 123 | 131 | | SecretMaterialDeleterService |
| 124 | 132 | > => |
| 125 | 133 | Effect.gen(function* () { |
| 126 | − const deps = yield* loadRuntimeSourceStoreDeps(executorState, input.workspaceId); | |
| 134 | + const deps = yield* loadRuntimeSourceStoreDeps(executorState, input.scopeId); | |
| 127 | 135 | const deleteSecretMaterial = yield* SecretMaterialDeleterService; |
| 128 | 136 | return yield* removeSourceByIdWithDeps(deps, input, deleteSecretMaterial); |
| 129 | 137 | }); |
| @@ -132,17 +140,17 @@ export const persistSource = ( · 2 unmodified lines | ||
| 132 | 140 | executorState: ExecutorStateStoreShape, |
| 133 | 141 | source: Source, |
| 134 | 142 | options: { |
| 135 | − actorAccountId?: AccountId | null; | |
| 143 | + actorScopeId?: ScopeId | null; | |
| 136 | 144 | } = {}, |
| 137 | 145 | ): Effect.Effect< |
| 138 | 146 | Source, |
| 139 | 147 | Error, |
| 140 | − | WorkspaceStorageServices | |
| 148 | + | ScopeStorageServices | |
| 141 | 149 | | SourceTypeDeclarationsRefresherService |
| 142 | 150 | | SecretMaterialDeleterService |
| 143 | 151 | > => |
| 144 | 152 | Effect.gen(function* () { |
| 145 | − const deps = yield* loadRuntimeSourceStoreDeps(executorState, source.workspaceId); | |
| 153 | + const deps = yield* loadRuntimeSourceStoreDeps(executorState, source.scopeId); | |
| 146 | 154 | const deleteSecretMaterial = yield* SecretMaterialDeleterService; |
| 147 | 155 | return yield* persistSourceWithDeps(deps, source, options, deleteSecretMaterial); |
| 148 | 156 | }); |
| @@ -155,9 +163,9 @@ export const RuntimeSourceStoreLive = Layer.effect( · 6 unmodified lines | ||
| 155 | 163 | RuntimeSourceStoreService, |
| 156 | 164 | Effect.gen(function* () { |
| 157 | 165 | const executorState = yield* ExecutorStateStore; |
| 158 | − const runtimeLocalWorkspace = yield* RuntimeLocalWorkspaceService; | |
| 159 | − const workspaceConfigStore = yield* WorkspaceConfigStore; | |
| 160 | − const workspaceStateStore = yield* WorkspaceStateStore; | |
| 166 | + const runtimeLocalScope = yield* RuntimeLocalScopeService; | |
| 167 | + const scopeConfigStore = yield* ScopeConfigStore; | |
| 168 | + const scopeStateStore = yield* ScopeStateStore; | |
| 161 | 169 | const sourceArtifactStore = yield* SourceArtifactStore; |
| 162 | 170 | const sourceTypeDeclarationsRefresher = |
| 163 | 171 | yield* SourceTypeDeclarationsRefresherService; |
| @@ -165,18 +173,18 @@ export const RuntimeSourceStoreLive = Layer.effect( · 1 unmodified line | ||
| 165 | 173 | |
| 166 | 174 | const deps: RuntimeSourceStoreDeps = { |
| 167 | 175 | executorState, |
| 168 | − runtimeLocalWorkspace, | |
| 169 | − workspaceConfigStore, | |
| 170 | − workspaceStateStore, | |
| 176 | + runtimeLocalScope, | |
| 177 | + scopeConfigStore, | |
| 178 | + scopeStateStore, | |
| 171 | 179 | sourceArtifactStore, |
| 172 | 180 | sourceTypeDeclarationsRefresher, |
| 173 | 181 | }; |
| 174 | 182 | |
| 175 | 183 | return RuntimeSourceStoreService.of({ |
| 176 | − loadSourcesInWorkspace: (workspaceId, options = {}) => | |
| 177 | − loadSourcesInWorkspaceWithDeps(deps, workspaceId, options), | |
| 178 | − listLinkedSecretSourcesInWorkspace: (workspaceId, options = {}) => | |
| 179 | − listLinkedSecretSourcesInWorkspaceWithDeps(deps, workspaceId, options), | |
| 184 | + loadSourcesInScope: (scopeId, options = {}) => | |
| 185 | + loadSourcesInWorkspaceWithDeps(deps, scopeId, options), | |
| 186 | + listLinkedSecretSourcesInScope: (scopeId, options = {}) => | |
| 187 | + listLinkedSecretSourcesInWorkspaceWithDeps(deps, scopeId, options), | |
| 180 | 188 | loadSourceById: (input) => |
| 181 | 189 | loadSourceByIdWithDeps(deps, input), |
| 182 | 190 | removeSourceById: (input) => |
| @@ -1,18 +1,27 @@ | ||
| 1 | 1 | import type { |
| 2 | − AccountId, | |
| 2 | + ScopeId, | |
| 3 | 3 | AuthArtifact, |
| 4 | 4 | CredentialSlot, |
| 5 | 5 | ProviderAuthGrant, |
| 6 | 6 | Source, |
| 7 | − WorkspaceId, | |
| 8 | 7 | } from "#schema"; |
| 9 | −import { decodeProviderGrantRefAuthArtifactConfig } from "#schema"; | |
| 8 | +import { | |
| 9 | + decodeProviderGrantRefAuthArtifactConfig, | |
| 10 | +} from "#schema"; | |
| 10 | 11 | import * as Effect from "effect/Effect"; |
| 11 | 12 | |
| 12 | −import { authArtifactSecretMaterialRefs } from "../../auth/auth-artifacts"; | |
| 13 | −import { removeAuthLeaseAndSecrets } from "../../auth/auth-leases"; | |
| 14 | −import type { DeleteSecretMaterial } from "../../workspace/secret-material-providers"; | |
| 15 | −import type { ExecutorStateStoreShape } from "../../executor-state-store"; | |
| 13 | +import { | |
| 14 | + authArtifactSecretMaterialRefs, | |
| 15 | +} from "../../auth/auth-artifacts"; | |
| 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 | 26 | const secretRefKey = (ref: { providerId: string; handle: string }): string => |
| 18 | 27 | `${ref.providerId}:${ref.handle}`; |
| @@ -60,52 +69,52 @@ export const providerGrantIdsFromArtifacts = ( · 41 unmodified lines | ||
| 60 | 69 | |
| 61 | 70 | export const selectPreferredAuthArtifact = (input: { |
| 62 | 71 | authArtifacts: ReadonlyArray<AuthArtifact>; |
| 63 | − actorAccountId?: AccountId | null; | |
| 72 | + actorScopeId?: ScopeId | null; | |
| 64 | 73 | slot: CredentialSlot; |
| 65 | 74 | }): AuthArtifact | null => { |
| 66 | 75 | const matchingSlot = input.authArtifacts.filter( |
| 67 | 76 | (artifact) => artifact.slot === input.slot, |
| 68 | 77 | ); |
| 69 | 78 | |
| 70 | − if (input.actorAccountId !== undefined) { | |
| 79 | + if (input.actorScopeId !== undefined) { | |
| 71 | 80 | const exact = matchingSlot.find( |
| 72 | − (artifact) => artifact.actorAccountId === input.actorAccountId, | |
| 81 | + (artifact) => artifact.actorScopeId === input.actorScopeId, | |
| 73 | 82 | ); |
| 74 | 83 | if (exact) { |
| 75 | 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 | 91 | export const selectExactAuthArtifact = (input: { |
| 83 | 92 | authArtifacts: ReadonlyArray<AuthArtifact>; |
| 84 | − actorAccountId?: AccountId | null; | |
| 93 | + actorScopeId?: ScopeId | null; | |
| 85 | 94 | slot: CredentialSlot; |
| 86 | 95 | }): AuthArtifact | null => |
| 87 | 96 | input.authArtifacts.find( |
| 88 | 97 | (artifact) => |
| 89 | 98 | artifact.slot === input.slot && |
| 90 | − artifact.actorAccountId === (input.actorAccountId ?? null), | |
| 99 | + artifact.actorScopeId === (input.actorScopeId ?? null), | |
| 91 | 100 | ) ?? null; |
| 92 | 101 | |
| 93 | 102 | export const removeAuthArtifactsForSource = ( |
| 94 | 103 | executorState: ExecutorStateStoreShape, |
| 95 | 104 | input: { |
| 96 | − workspaceId: WorkspaceId; | |
| 105 | + scopeId: ScopeId; | |
| 97 | 106 | sourceId: Source["id"]; |
| 98 | 107 | }, |
| 99 | 108 | deleteSecretMaterial: DeleteSecretMaterial, |
| 100 | 109 | ) => |
| 101 | 110 | Effect.gen(function* () { |
| 102 | − const existingAuthArtifacts = yield* executorState.authArtifacts.listByWorkspaceAndSourceId({ | |
| 103 | − workspaceId: input.workspaceId, | |
| 111 | + const existingAuthArtifacts = yield* executorState.authArtifacts.listByScopeAndSourceId({ | |
| 112 | + scopeId: input.scopeId, | |
| 104 | 113 | sourceId: input.sourceId, |
| 105 | 114 | }); |
| 106 | 115 | |
| 107 | − yield* executorState.authArtifacts.removeByWorkspaceAndSourceId({ | |
| 108 | − workspaceId: input.workspaceId, | |
| 116 | + yield* executorState.authArtifacts.removeByScopeAndSourceId({ | |
| 117 | + scopeId: input.scopeId, | |
| 109 | 118 | sourceId: input.sourceId, |
| 110 | 119 | }); |
| 111 | 120 | |
| @@ -4,16 +4,26 @@ import type { · 3 unmodified lines | ||
| 4 | 4 | Source, |
| 5 | 5 | SourceId, |
| 6 | 6 | } from "#schema"; |
| 7 | −import { SourceIdSchema } from "#schema"; | |
| 7 | +import { | |
| 8 | + SourceIdSchema, | |
| 9 | +} from "#schema"; | |
| 8 | 10 | |
| 9 | −import type { LoadedLocalExecutorConfig } from "../../workspace-config"; | |
| 10 | −import { LocalUnsupportedSourceKindError } from "../../workspace-errors"; | |
| 11 | +import type { | |
| 12 | + LoadedLocalExecutorConfig, | |
| 13 | +} from "../../scope-config"; | |
| 14 | +import { | |
| 15 | + LocalUnsupportedSourceKindError, | |
| 16 | +} from "../../scope-errors"; | |
| 11 | 17 | import { |
| 12 | 18 | fromConfigSecretProviderId, |
| 13 | 19 | toConfigSecretProviderId, |
| 14 | −} from "../../workspace/config-secrets"; | |
| 15 | −import { getSourceAdapterForSource } from "../source-adapters"; | |
| 16 | −import { slugify } from "../slug"; | |
| 20 | +} from "../../scope/config-secrets"; | |
| 21 | +import { | |
| 22 | + getSourceAdapterForSource, | |
| 23 | +} from "../source-adapters"; | |
| 24 | +import { | |
| 25 | + slugify, | |
| 26 | +} from "../slug"; | |
| 17 | 27 | |
| 18 | 28 | export const trimOrNull = (value: string | null | undefined): string | null => { |
| 19 | 29 | if (value == null) { |
| @@ -1,112 +1,120 @@ | ||
| 1 | −import type { AccountId, WorkspaceId } from "#schema"; | |
| 1 | +import type { | |
| 2 | + ScopeId, | |
| 3 | +} from "#schema"; | |
| 2 | 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 | 9 | import { |
| 6 | 10 | SourceTypeDeclarationsRefresherService, |
| 7 | 11 | type SourceTypeDeclarationsRefresherShape, |
| 8 | 12 | } from "../../catalog/source/type-declarations"; |
| 9 | 13 | import { |
| 10 | − RuntimeLocalWorkspaceMismatchError, | |
| 11 | − RuntimeLocalWorkspaceUnavailableError, | |
| 12 | −} from "../../workspace-errors"; | |
| 14 | + RuntimeLocalScopeMismatchError, | |
| 15 | + RuntimeLocalScopeUnavailableError, | |
| 16 | +} from "../../scope-errors"; | |
| 13 | 17 | import { |
| 14 | − requireRuntimeLocalWorkspace, | |
| 15 | − type RuntimeLocalWorkspaceState, | |
| 16 | −} from "../../workspace/runtime-context"; | |
| 18 | + requireRuntimeLocalScope, | |
| 19 | + type RuntimeLocalScopeState, | |
| 20 | +} from "../../scope/runtime-context"; | |
| 17 | 21 | import type { |
| 18 | 22 | SourceArtifactStoreShape, |
| 19 | − WorkspaceStorageServices, | |
| 20 | − WorkspaceConfigStoreShape, | |
| 21 | − WorkspaceStateStoreShape, | |
| 22 | −} from "../../workspace/storage"; | |
| 23 | + ScopeStorageServices, | |
| 24 | + ScopeConfigStoreShape, | |
| 25 | + ScopeStateStoreShape, | |
| 26 | +} from "../../scope/storage"; | |
| 23 | 27 | import { |
| 24 | 28 | SourceArtifactStore, |
| 25 | − WorkspaceConfigStore, | |
| 26 | − WorkspaceStateStore, | |
| 27 | −} from "../../workspace/storage"; | |
| 28 | −import type { LocalWorkspaceState } from "../../workspace-state"; | |
| 29 | −import type { ExecutorStateStoreShape } from "../../executor-state-store"; | |
| 29 | + ScopeConfigStore, | |
| 30 | + ScopeStateStore, | |
| 31 | +} from "../../scope/storage"; | |
| 32 | +import type { | |
| 33 | + LocalScopeState, | |
| 34 | +} from "../../scope-state"; | |
| 35 | +import type { | |
| 36 | + ExecutorStateStoreShape, | |
| 37 | +} from "../../executor-state-store"; | |
| 30 | 38 | |
| 31 | 39 | export type RuntimeSourceStoreDeps = { |
| 32 | 40 | executorState: ExecutorStateStoreShape; |
| 33 | − runtimeLocalWorkspace: RuntimeLocalWorkspaceState; | |
| 34 | − workspaceConfigStore: WorkspaceConfigStoreShape; | |
| 35 | − workspaceStateStore: WorkspaceStateStoreShape; | |
| 41 | + runtimeLocalScope: RuntimeLocalScopeState; | |
| 42 | + scopeConfigStore: ScopeConfigStoreShape; | |
| 43 | + scopeStateStore: ScopeStateStoreShape; | |
| 36 | 44 | sourceArtifactStore: SourceArtifactStoreShape; |
| 37 | 45 | sourceTypeDeclarationsRefresher: SourceTypeDeclarationsRefresherShape; |
| 38 | 46 | }; |
| 39 | 47 | |
| 40 | −export type ResolvedSourceStoreWorkspace = { | |
| 48 | +export type ResolvedSourceStoreScope = { | |
| 41 | 49 | installation: { |
| 42 | − workspaceId: WorkspaceId; | |
| 43 | − accountId: AccountId; | |
| 50 | + scopeId: ScopeId; | |
| 51 | + actorScopeId: ScopeId; | |
| 44 | 52 | }; |
| 45 | − workspaceConfigStore: WorkspaceConfigStoreShape; | |
| 46 | − workspaceStateStore: WorkspaceStateStoreShape; | |
| 53 | + scopeConfigStore: ScopeConfigStoreShape; | |
| 54 | + scopeStateStore: ScopeStateStoreShape; | |
| 47 | 55 | sourceArtifactStore: SourceArtifactStoreShape; |
| 48 | 56 | loadedConfig: LoadedLocalExecutorConfig; |
| 49 | − workspaceState: LocalWorkspaceState; | |
| 57 | + scopeState: LocalScopeState; | |
| 50 | 58 | }; |
| 51 | 59 | |
| 52 | 60 | export type RuntimeSourceStoreServices = |
| 53 | − WorkspaceStorageServices | SourceTypeDeclarationsRefresherService; | |
| 61 | + ScopeStorageServices | SourceTypeDeclarationsRefresherService; | |
| 54 | 62 | |
| 55 | −export const resolveRuntimeLocalWorkspaceFromDeps = ( | |
| 63 | +export const resolveRuntimeLocalScopeFromDeps = ( | |
| 56 | 64 | deps: RuntimeSourceStoreDeps, |
| 57 | − workspaceId: WorkspaceId, | |
| 65 | + scopeId: ScopeId, | |
| 58 | 66 | ): Effect.Effect< |
| 59 | − ResolvedSourceStoreWorkspace, | |
| 60 | − | RuntimeLocalWorkspaceUnavailableError | |
| 61 | − | RuntimeLocalWorkspaceMismatchError | |
| 67 | + ResolvedSourceStoreScope, | |
| 68 | + | RuntimeLocalScopeUnavailableError | |
| 69 | + | RuntimeLocalScopeMismatchError | |
| 62 | 70 | | Error, |
| 63 | 71 | never |
| 64 | 72 | > => |
| 65 | 73 | Effect.gen(function* () { |
| 66 | − if (deps.runtimeLocalWorkspace.installation.workspaceId !== workspaceId) { | |
| 67 | − return yield* new RuntimeLocalWorkspaceMismatchError({ | |
| 68 | − message: `Runtime local workspace mismatch: expected ${workspaceId}, got ${deps.runtimeLocalWorkspace.installation.workspaceId}`, | |
| 69 | − requestedWorkspaceId: workspaceId, | |
| 70 | − activeWorkspaceId: deps.runtimeLocalWorkspace.installation.workspaceId, | |
| 74 | + if (deps.runtimeLocalScope.installation.scopeId !== scopeId) { | |
| 75 | + return yield* new RuntimeLocalScopeMismatchError({ | |
| 76 | + message: `Runtime local scope mismatch: expected ${scopeId}, got ${deps.runtimeLocalScope.installation.scopeId}`, | |
| 77 | + requestedScopeId: scopeId, | |
| 78 | + activeScopeId: deps.runtimeLocalScope.installation.scopeId, | |
| 71 | 79 | }); |
| 72 | 80 | } |
| 73 | 81 | |
| 74 | − const loadedConfig = yield* deps.workspaceConfigStore.load(); | |
| 75 | − const workspaceState = yield* deps.workspaceStateStore.load(); | |
| 82 | + const loadedConfig = yield* deps.scopeConfigStore.load(); | |
| 83 | + const scopeState = yield* deps.scopeStateStore.load(); | |
| 76 | 84 | |
| 77 | 85 | return { |
| 78 | − installation: deps.runtimeLocalWorkspace.installation, | |
| 79 | − workspaceConfigStore: deps.workspaceConfigStore, | |
| 80 | − workspaceStateStore: deps.workspaceStateStore, | |
| 86 | + installation: deps.runtimeLocalScope.installation, | |
| 87 | + scopeConfigStore: deps.scopeConfigStore, | |
| 88 | + scopeStateStore: deps.scopeStateStore, | |
| 81 | 89 | sourceArtifactStore: deps.sourceArtifactStore, |
| 82 | 90 | loadedConfig, |
| 83 | − workspaceState, | |
| 91 | + scopeState, | |
| 84 | 92 | }; |
| 85 | 93 | }); |
| 86 | 94 | |
| 87 | 95 | export const loadRuntimeSourceStoreDeps = ( |
| 88 | 96 | executorState: ExecutorStateStoreShape, |
| 89 | − workspaceId: WorkspaceId, | |
| 97 | + scopeId: ScopeId, | |
| 90 | 98 | ): Effect.Effect< |
| 91 | 99 | RuntimeSourceStoreDeps, |
| 92 | − | RuntimeLocalWorkspaceUnavailableError | |
| 93 | − | RuntimeLocalWorkspaceMismatchError | |
| 100 | + | RuntimeLocalScopeUnavailableError | |
| 101 | + | RuntimeLocalScopeMismatchError | |
| 94 | 102 | | Error, |
| 95 | 103 | RuntimeSourceStoreServices |
| 96 | 104 | > => |
| 97 | 105 | Effect.gen(function* () { |
| 98 | − const runtimeLocalWorkspace = yield* requireRuntimeLocalWorkspace(workspaceId); | |
| 99 | − const workspaceConfigStore = yield* WorkspaceConfigStore; | |
| 100 | − const workspaceStateStore = yield* WorkspaceStateStore; | |
| 106 | + const runtimeLocalScope = yield* requireRuntimeLocalScope(scopeId); | |
| 107 | + const scopeConfigStore = yield* ScopeConfigStore; | |
| 108 | + const scopeStateStore = yield* ScopeStateStore; | |
| 101 | 109 | const sourceArtifactStore = yield* SourceArtifactStore; |
| 102 | 110 | const sourceTypeDeclarationsRefresher = |
| 103 | 111 | yield* SourceTypeDeclarationsRefresherService; |
| 104 | 112 | |
| 105 | 113 | return { |
| 106 | 114 | executorState, |
| 107 | − runtimeLocalWorkspace, | |
| 108 | − workspaceConfigStore, | |
| 109 | − workspaceStateStore, | |
| 115 | + runtimeLocalScope, | |
| 116 | + scopeConfigStore, | |
| 117 | + scopeStateStore, | |
| 110 | 118 | sourceArtifactStore, |
| 111 | 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 | 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 | 10 | import { |
| 6 | 11 | clearProviderGrantOrphanedAt, |
| 7 | 12 | markProviderGrantOrphanedIfUnused, |
| 8 | 13 | } from "../../auth/provider-grant-lifecycle"; |
| 9 | −import type { DeleteSecretMaterial } from "../../workspace/secret-material-providers"; | |
| 10 | −import type { LocalWorkspaceState } from "../../workspace-state"; | |
| 14 | +import type { | |
| 15 | + DeleteSecretMaterial, | |
| 16 | +} from "../../scope/secret-material-providers"; | |
| 17 | +import type { | |
| 18 | + LocalScopeState, | |
| 19 | +} from "../../scope-state"; | |
| 11 | 20 | import { |
| 12 | 21 | stableSourceCatalogId, |
| 13 | 22 | stableSourceCatalogRevisionId, |
| @@ -26,37 +35,37 @@ import { · 12 unmodified lines | ||
| 26 | 35 | } from "./config"; |
| 27 | 36 | import { |
| 28 | 37 | type RuntimeSourceStoreDeps, |
| 29 | − resolveRuntimeLocalWorkspaceFromDeps, | |
| 38 | + resolveRuntimeLocalScopeFromDeps, | |
| 30 | 39 | } from "./deps"; |
| 31 | 40 | import { |
| 32 | 41 | loadSourceByIdWithDeps, |
| 33 | − shouldRefreshWorkspaceDeclarationsAfterPersist, | |
| 34 | − syncWorkspaceSourceTypeDeclarationsWithDeps, | |
| 42 | + shouldRefreshScopeDeclarationsAfterPersist, | |
| 43 | + syncScopeSourceTypeDeclarationsWithDeps, | |
| 35 | 44 | } from "./records"; |
| 36 | 45 | |
| 37 | 46 | export const removeSourceByIdWithDeps = ( |
| 38 | 47 | deps: RuntimeSourceStoreDeps, |
| 39 | 48 | input: { |
| 40 | − workspaceId: WorkspaceId; | |
| 49 | + scopeId: ScopeId; | |
| 41 | 50 | sourceId: Source["id"]; |
| 42 | 51 | }, |
| 43 | 52 | deleteSecretMaterial: DeleteSecretMaterial, |
| 44 | 53 | ): Effect.Effect<boolean, Error, never> => |
| 45 | 54 | Effect.gen(function* () { |
| 46 | − const localWorkspace = yield* resolveRuntimeLocalWorkspaceFromDeps( | |
| 55 | + const localScope = yield* resolveRuntimeLocalScopeFromDeps( | |
| 47 | 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 | 60 | return false; |
| 52 | 61 | } |
| 53 | 62 | |
| 54 | − const projectConfig = cloneJson(localWorkspace.loadedConfig.projectConfig ?? {}); | |
| 63 | + const projectConfig = cloneJson(localScope.loadedConfig.projectConfig ?? {}); | |
| 55 | 64 | const sources = { |
| 56 | 65 | ...projectConfig.sources, |
| 57 | 66 | }; |
| 58 | 67 | delete sources[input.sourceId]; |
| 59 | − yield* localWorkspace.workspaceConfigStore.writeProject({ | |
| 68 | + yield* localScope.scopeConfigStore.writeProject({ | |
| 60 | 69 | config: { |
| 61 | 70 | ...projectConfig, |
| 62 | 71 | sources, |
| @@ -64,30 +73,30 @@ export const removeSourceByIdWithDeps = ( · 1 unmodified line | ||
| 64 | 73 | }); |
| 65 | 74 | |
| 66 | 75 | const { [input.sourceId]: _removedSource, ...remainingSources } = |
| 67 | − localWorkspace.workspaceState.sources; | |
| 68 | − const workspaceState: LocalWorkspaceState = { | |
| 69 | − ...localWorkspace.workspaceState, | |
| 76 | + localScope.scopeState.sources; | |
| 77 | + const scopeState: LocalScopeState = { | |
| 78 | + ...localScope.scopeState, | |
| 70 | 79 | sources: remainingSources, |
| 71 | 80 | }; |
| 72 | − yield* localWorkspace.workspaceStateStore.write({ | |
| 73 | − state: workspaceState, | |
| 81 | + yield* localScope.scopeStateStore.write({ | |
| 82 | + state: scopeState, | |
| 74 | 83 | }); |
| 75 | − yield* localWorkspace.sourceArtifactStore.remove({ | |
| 84 | + yield* localScope.sourceArtifactStore.remove({ | |
| 76 | 85 | sourceId: input.sourceId, |
| 77 | 86 | }); |
| 78 | 87 | const existingAuthArtifacts = |
| 79 | − yield* deps.executorState.authArtifacts.listByWorkspaceAndSourceId({ | |
| 80 | − workspaceId: input.workspaceId, | |
| 88 | + yield* deps.executorState.authArtifacts.listByScopeAndSourceId({ | |
| 89 | + scopeId: input.scopeId, | |
| 81 | 90 | sourceId: input.sourceId, |
| 82 | 91 | }); |
| 83 | 92 | const removedGrantIds = providerGrantIdsFromArtifacts(existingAuthArtifacts); |
| 84 | 93 | |
| 85 | − yield* deps.executorState.sourceAuthSessions.removeByWorkspaceAndSourceId( | |
| 86 | − input.workspaceId, | |
| 94 | + yield* deps.executorState.sourceAuthSessions.removeByScopeAndSourceId( | |
| 95 | + input.scopeId, | |
| 87 | 96 | input.sourceId, |
| 88 | 97 | ); |
| 89 | − yield* deps.executorState.sourceOauthClients.removeByWorkspaceAndSourceId({ | |
| 90 | − workspaceId: input.workspaceId, | |
| 98 | + yield* deps.executorState.sourceOauthClients.removeByScopeAndSourceId({ | |
| 99 | + scopeId: input.scopeId, | |
| 91 | 100 | sourceId: input.sourceId, |
| 92 | 101 | }); |
| 93 | 102 | yield* removeAuthArtifactsForSource(deps.executorState, input, deleteSecretMaterial); |
| @@ -95,12 +104,12 @@ export const removeSourceByIdWithDeps = ( · 1 unmodified line | ||
| 95 | 104 | [...removedGrantIds], |
| 96 | 105 | (grantId) => |
| 97 | 106 | markProviderGrantOrphanedIfUnused(deps.executorState, { |
| 98 | − workspaceId: input.workspaceId, | |
| 107 | + scopeId: input.scopeId, | |
| 99 | 108 | grantId, |
| 100 | 109 | }), |
| 101 | 110 | { discard: true }, |
| 102 | 111 | ); |
| 103 | − yield* syncWorkspaceSourceTypeDeclarationsWithDeps(deps, input.workspaceId); | |
| 112 | + yield* syncScopeSourceTypeDeclarationsWithDeps(deps, input.scopeId); | |
| 104 | 113 | |
| 105 | 114 | return true; |
| 106 | 115 | }); |
| @@ -109,42 +118,42 @@ export const persistSourceWithDeps = ( · 2 unmodified lines | ||
| 109 | 118 | deps: RuntimeSourceStoreDeps, |
| 110 | 119 | source: Source, |
| 111 | 120 | options: { |
| 112 | − actorAccountId?: AccountId | null; | |
| 121 | + actorScopeId?: ScopeId | null; | |
| 113 | 122 | } = {}, |
| 114 | 123 | deleteSecretMaterial: DeleteSecretMaterial, |
| 115 | 124 | ): Effect.Effect<Source, Error, never> => |
| 116 | 125 | Effect.gen(function* () { |
| 117 | − const localWorkspace = yield* resolveRuntimeLocalWorkspaceFromDeps( | |
| 126 | + const localScope = yield* resolveRuntimeLocalScopeFromDeps( | |
| 118 | 127 | deps, |
| 119 | − source.workspaceId, | |
| 128 | + source.scopeId, | |
| 120 | 129 | ); |
| 121 | 130 | const nextSource = { |
| 122 | 131 | ...source, |
| 123 | 132 | id: |
| 124 | − localWorkspace.loadedConfig.config?.sources?.[source.id] || | |
| 125 | − localWorkspace.workspaceState.sources[source.id] | |
| 133 | + localScope.loadedConfig.config?.sources?.[source.id] || | |
| 134 | + localScope.scopeState.sources[source.id] | |
| 126 | 135 | ? source.id |
| 127 | 136 | : deriveLocalSourceId( |
| 128 | 137 | source, |
| 129 | − new Set(Object.keys(localWorkspace.loadedConfig.config?.sources ?? {})), | |
| 138 | + new Set(Object.keys(localScope.loadedConfig.config?.sources ?? {})), | |
| 130 | 139 | ), |
| 131 | 140 | } satisfies Source; |
| 132 | 141 | const existingAuthArtifacts = |
| 133 | − yield* deps.executorState.authArtifacts.listByWorkspaceAndSourceId({ | |
| 134 | − workspaceId: nextSource.workspaceId, | |
| 142 | + yield* deps.executorState.authArtifacts.listByScopeAndSourceId({ | |
| 143 | + scopeId: nextSource.scopeId, | |
| 135 | 144 | sourceId: nextSource.id, |
| 136 | 145 | }); |
| 137 | 146 | const existingRuntimeAuthArtifact = selectExactAuthArtifact({ |
| 138 | 147 | authArtifacts: existingAuthArtifacts, |
| 139 | − actorAccountId: options.actorAccountId, | |
| 148 | + actorScopeId: options.actorScopeId, | |
| 140 | 149 | slot: "runtime", |
| 141 | 150 | }); |
| 142 | 151 | const existingImportAuthArtifact = selectExactAuthArtifact({ |
| 143 | 152 | authArtifacts: existingAuthArtifacts, |
| 144 | − actorAccountId: options.actorAccountId, | |
| 153 | + actorScopeId: options.actorScopeId, | |
| 145 | 154 | slot: "import", |
| 146 | 155 | }); |
| 147 | − const projectConfig = cloneJson(localWorkspace.loadedConfig.projectConfig ?? {}); | |
| 156 | + const projectConfig = cloneJson(localScope.loadedConfig.projectConfig ?? {}); | |
| 148 | 157 | const sources = { |
| 149 | 158 | ...projectConfig.sources, |
| 150 | 159 | }; |
| @@ -152,9 +161,9 @@ export const persistSourceWithDeps = ( · 1 unmodified line | ||
| 152 | 161 | sources[nextSource.id] = configSourceFromLocalSource({ |
| 153 | 162 | source: nextSource, |
| 154 | 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 | 167 | config: { |
| 159 | 168 | ...projectConfig, |
| 160 | 169 | sources, |
| @@ -165,7 +174,7 @@ export const persistSourceWithDeps = ( · 4 unmodified lines | ||
| 165 | 174 | source: nextSource, |
| 166 | 175 | catalogId: stableSourceCatalogId(nextSource), |
| 167 | 176 | catalogRevisionId: stableSourceCatalogRevisionId(nextSource), |
| 168 | − actorAccountId: options.actorAccountId, | |
| 177 | + actorScopeId: options.actorScopeId, | |
| 169 | 178 | existingRuntimeAuthArtifactId: existingRuntimeAuthArtifact?.id ?? null, |
| 170 | 179 | existingImportAuthArtifactId: existingImportAuthArtifact?.id ?? null, |
| 171 | 180 | }); |
| @@ -176,10 +185,10 @@ export const persistSourceWithDeps = ( · 4 unmodified lines | ||
| 176 | 185 | authArtifactId: existingRuntimeAuthArtifact.id, |
| 177 | 186 | }, deleteSecretMaterial); |
| 178 | 187 | } |
| 179 | − yield* deps.executorState.authArtifacts.removeByWorkspaceSourceAndActor({ | |
| 180 | − workspaceId: nextSource.workspaceId, | |
| 188 | + yield* deps.executorState.authArtifacts.removeByScopeSourceAndActor({ | |
| 189 | + scopeId: nextSource.scopeId, | |
| 181 | 190 | sourceId: nextSource.id, |
| 182 | − actorAccountId: options.actorAccountId ?? null, | |
| 191 | + actorScopeId: options.actorScopeId ?? null, | |
| 183 | 192 | slot: "runtime", |
| 184 | 193 | }); |
| 185 | 194 | } else { |
| @@ -205,10 +214,10 @@ export const persistSourceWithDeps = ( · 19 unmodified lines | ||
| 205 | 214 | authArtifactId: existingImportAuthArtifact.id, |
| 206 | 215 | }, deleteSecretMaterial); |
| 207 | 216 | } |
| 208 | − yield* deps.executorState.authArtifacts.removeByWorkspaceSourceAndActor({ | |
| 209 | − workspaceId: nextSource.workspaceId, | |
| 217 | + yield* deps.executorState.authArtifacts.removeByScopeSourceAndActor({ | |
| 218 | + scopeId: nextSource.scopeId, | |
| 210 | 219 | sourceId: nextSource.id, |
| 211 | − actorAccountId: options.actorAccountId ?? null, | |
| 220 | + actorScopeId: options.actorScopeId ?? null, | |
| 212 | 221 | slot: "import", |
| 213 | 222 | }); |
| 214 | 223 | } else { |
| @@ -249,17 +258,17 @@ export const persistSourceWithDeps = ( · 34 unmodified lines | ||
| 249 | 258 | [...previousGrantIds].filter((grantId) => !nextGrantIds.has(grantId)), |
| 250 | 259 | (grantId) => |
| 251 | 260 | markProviderGrantOrphanedIfUnused(deps.executorState, { |
| 252 | − workspaceId: nextSource.workspaceId, | |
| 261 | + scopeId: nextSource.scopeId, | |
| 253 | 262 | grantId, |
| 254 | 263 | }), |
| 255 | 264 | { discard: true }, |
| 256 | 265 | ); |
| 257 | 266 | |
| 258 | − const existingSourceState = localWorkspace.workspaceState.sources[nextSource.id]; | |
| 259 | − const workspaceState: LocalWorkspaceState = { | |
| 260 | − ...localWorkspace.workspaceState, | |
| 267 | + const existingSourceState = localScope.scopeState.sources[nextSource.id]; | |
| 268 | + const scopeState: LocalScopeState = { | |
| 269 | + ...localScope.scopeState, | |
| 261 | 270 | sources: { |
| 262 | − ...localWorkspace.workspaceState.sources, | |
| 271 | + ...localScope.scopeState.sources, | |
| 263 | 272 | [nextSource.id]: { |
| 264 | 273 | status: nextSource.status, |
| 265 | 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({ | |
| 273 | − state: workspaceState, | |
| 281 | + yield* localScope.scopeStateStore.write({ | |
| 282 | + state: scopeState, | |
| 274 | 283 | }); |
| 275 | 284 | |
| 276 | − if (shouldRefreshWorkspaceDeclarationsAfterPersist(nextSource)) { | |
| 277 | − yield* syncWorkspaceSourceTypeDeclarationsWithDeps( | |
| 285 | + if (shouldRefreshScopeDeclarationsAfterPersist(nextSource)) { | |
| 286 | + yield* syncScopeSourceTypeDeclarationsWithDeps( | |
| 278 | 287 | deps, |
| 279 | − nextSource.workspaceId, | |
| 288 | + nextSource.scopeId, | |
| 280 | 289 | options, |
| 281 | 290 | ); |
| 282 | 291 | } |
| 283 | 292 | |
| 284 | 293 | return yield* loadSourceByIdWithDeps(deps, { |
| 285 | − workspaceId: nextSource.workspaceId, | |
| 294 | + scopeId: nextSource.scopeId, | |
| 286 | 295 | sourceId: nextSource.id, |
| 287 | − actorAccountId: options.actorAccountId, | |
| 296 | + actorScopeId: options.actorScopeId, | |
| 288 | 297 | }); |
| 289 | 298 | }).pipe( |
| 290 | 299 | Effect.withSpan("source.store.persist", { |
| 291 | 300 | attributes: { |
| 292 | − "executor.workspace.id": source.workspaceId, | |
| 301 | + "executor.scope.id": source.scopeId, | |
| 293 | 302 | "executor.source.id": source.id, |
| 294 | 303 | "executor.source.kind": source.kind, |
| 295 | 304 | "executor.source.status": source.status, |
| @@ -1,25 +1,36 @@ | ||
| 1 | 1 | import type { |
| 2 | − AccountId, | |
| 2 | + ScopeId, | |
| 3 | 3 | AuthArtifact, |
| 4 | 4 | Source, |
| 5 | 5 | SourceId, |
| 6 | − WorkspaceId, | |
| 7 | 6 | } from "#schema"; |
| 8 | −import { SourceIdSchema } from "#schema"; | |
| 7 | +import { | |
| 8 | + SourceIdSchema, | |
| 9 | +} from "#schema"; | |
| 9 | 10 | import * as Effect from "effect/Effect"; |
| 10 | 11 | |
| 11 | −import { sourceAuthFromAuthArtifact } from "../../auth/auth-artifacts"; | |
| 12 | −import { authArtifactSecretMaterialRefs } from "../../auth/auth-artifacts"; | |
| 13 | −import type { LoadedLocalExecutorConfig } from "../../workspace-config"; | |
| 12 | +import { | |
| 13 | + sourceAuthFromAuthArtifact, | |
| 14 | +} from "../../auth/auth-artifacts"; | |
| 15 | +import { | |
| 16 | + authArtifactSecretMaterialRefs, | |
| 17 | +} from "../../auth/auth-artifacts"; | |
| 18 | +import type { | |
| 19 | + LoadedLocalExecutorConfig, | |
| 20 | +} from "../../scope-config"; | |
| 14 | 21 | import { |
| 15 | 22 | LocalConfiguredSourceNotFoundError, |
| 16 | − RuntimeLocalWorkspaceMismatchError, | |
| 17 | − RuntimeLocalWorkspaceUnavailableError, | |
| 18 | −} from "../../workspace-errors"; | |
| 19 | −import type { LocalWorkspaceState } from "../../workspace-state"; | |
| 20 | −import { getSourceAdapter } from "../source-adapters"; | |
| 23 | + RuntimeLocalScopeMismatchError, | |
| 24 | + RuntimeLocalScopeUnavailableError, | |
| 25 | +} from "../../scope-errors"; | |
| 26 | +import type { | |
| 27 | + LocalScopeState, | |
| 28 | +} from "../../scope-state"; | |
| 29 | +import { | |
| 30 | + getSourceAdapter, | |
| 31 | +} from "../source-adapters"; | |
| 21 | 32 | import { |
| 22 | − resolveRuntimeLocalWorkspaceFromDeps, | |
| 33 | + resolveRuntimeLocalScopeFromDeps, | |
| 23 | 34 | type RuntimeSourceStoreDeps, |
| 24 | 35 | } from "./deps"; |
| 25 | 36 | import { |
| @@ -31,11 +42,11 @@ import { · 5 unmodified lines | ||
| 31 | 42 | } from "./config"; |
| 32 | 43 | |
| 33 | 44 | export const buildLocalSourceRecord = (input: { |
| 34 | − workspaceId: WorkspaceId; | |
| 45 | + scopeId: ScopeId; | |
| 35 | 46 | loadedConfig: LoadedLocalExecutorConfig; |
| 36 | − workspaceState: LocalWorkspaceState; | |
| 47 | + scopeState: LocalScopeState; | |
| 37 | 48 | sourceId: SourceId; |
| 38 | − actorAccountId?: AccountId | null; | |
| 49 | + actorScopeId?: ScopeId | null; | |
| 39 | 50 | authArtifacts: ReadonlyArray<AuthArtifact>; |
| 40 | 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 | 69 | const adapter = getSourceAdapter(sourceConfig.kind); |
| 59 | 70 | const baseSource = (yield* adapter.validateSource({ |
| 60 | 71 | id: SourceIdSchema.make(input.sourceId), |
| 61 | − workspaceId: input.workspaceId, | |
| 72 | + scopeId: input.scopeId, | |
| 62 | 73 | name: trimOrNull(sourceConfig.name) ?? input.sourceId, |
| 63 | 74 | kind: sourceConfig.kind, |
| 64 | 75 | endpoint: sourceConfig.connection.endpoint.trim(), |
| @@ -86,14 +97,14 @@ export const buildLocalSourceRecord = (input: { · 21 unmodified lines | ||
| 86 | 97 | authArtifacts: input.authArtifacts.filter( |
| 87 | 98 | (artifactItem) => artifactItem.sourceId === baseSource.id, |
| 88 | 99 | ), |
| 89 | − actorAccountId: input.actorAccountId, | |
| 100 | + actorScopeId: input.actorScopeId, | |
| 90 | 101 | slot: "runtime", |
| 91 | 102 | }); |
| 92 | 103 | const importAuthArtifact = selectPreferredAuthArtifact({ |
| 93 | 104 | authArtifacts: input.authArtifacts.filter( |
| 94 | 105 | (artifactItem) => artifactItem.sourceId === baseSource.id, |
| 95 | 106 | ), |
| 96 | − actorAccountId: input.actorAccountId, | |
| 107 | + actorScopeId: input.actorScopeId, | |
| 97 | 108 | slot: "import", |
| 98 | 109 | }); |
| 99 | 110 | |
| @@ -119,36 +130,36 @@ export const buildLocalSourceRecord = (input: { · 19 unmodified lines | ||
| 119 | 130 | |
| 120 | 131 | export const loadSourcesInWorkspaceWithDeps = ( |
| 121 | 132 | deps: RuntimeSourceStoreDeps, |
| 122 | − workspaceId: WorkspaceId, | |
| 133 | + scopeId: ScopeId, | |
| 123 | 134 | options: { |
| 124 | − actorAccountId?: AccountId | null; | |
| 135 | + actorScopeId?: ScopeId | null; | |
| 125 | 136 | } = {}, |
| 126 | 137 | ): Effect.Effect< |
| 127 | 138 | readonly Source[], |
| 128 | − | RuntimeLocalWorkspaceUnavailableError | |
| 129 | − | RuntimeLocalWorkspaceMismatchError | |
| 139 | + | RuntimeLocalScopeUnavailableError | |
| 140 | + | RuntimeLocalScopeMismatchError | |
| 130 | 141 | | LocalConfiguredSourceNotFoundError |
| 131 | 142 | | Error, |
| 132 | 143 | never |
| 133 | 144 | > => |
| 134 | 145 | Effect.gen(function* () { |
| 135 | − const localWorkspace = yield* resolveRuntimeLocalWorkspaceFromDeps( | |
| 146 | + const localScope = yield* resolveRuntimeLocalScopeFromDeps( | |
| 136 | 147 | deps, |
| 137 | − workspaceId, | |
| 148 | + scopeId, | |
| 138 | 149 | ); |
| 139 | − const authArtifacts = yield* deps.executorState.authArtifacts.listByWorkspaceId( | |
| 140 | − workspaceId, | |
| 150 | + const authArtifacts = yield* deps.executorState.authArtifacts.listByScopeId( | |
| 151 | + scopeId, | |
| 141 | 152 | ); |
| 142 | 153 | const sources = yield* Effect.forEach( |
| 143 | − Object.keys(localWorkspace.loadedConfig.config?.sources ?? {}), | |
| 154 | + Object.keys(localScope.loadedConfig.config?.sources ?? {}), | |
| 144 | 155 | (sourceId) => |
| 145 | 156 | Effect.map( |
| 146 | 157 | buildLocalSourceRecord({ |
| 147 | − workspaceId, | |
| 148 | − loadedConfig: localWorkspace.loadedConfig, | |
| 149 | − workspaceState: localWorkspace.workspaceState, | |
| 158 | + scopeId, | |
| 159 | + loadedConfig: localScope.loadedConfig, | |
| 160 | + scopeState: localScope.scopeState, | |
| 150 | 161 | sourceId: SourceIdSchema.make(sourceId), |
| 151 | − actorAccountId: options.actorAccountId, | |
| 162 | + actorScopeId: options.actorScopeId, | |
| 152 | 163 | authArtifacts, |
| 153 | 164 | }), |
| 154 | 165 | ({ source }) => source, |
| @@ -157,28 +168,28 @@ export const loadSourcesInWorkspaceWithDeps = ( · 2 unmodified lines | ||
| 157 | 168 | yield* Effect.annotateCurrentSpan("executor.source.count", sources.length); |
| 158 | 169 | return sources; |
| 159 | 170 | }).pipe( |
| 160 | − Effect.withSpan("source.store.load_workspace", { | |
| 171 | + Effect.withSpan("source.store.load_scope", { | |
| 161 | 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 | 179 | deps: RuntimeSourceStoreDeps, |
| 169 | − workspaceId: WorkspaceId, | |
| 180 | + scopeId: ScopeId, | |
| 170 | 181 | options: { |
| 171 | − actorAccountId?: AccountId | null; | |
| 182 | + actorScopeId?: ScopeId | null; | |
| 172 | 183 | } = {}, |
| 173 | 184 | ): Effect.Effect<void, Error, never> => |
| 174 | 185 | Effect.gen(function* () { |
| 175 | − const localWorkspace = yield* resolveRuntimeLocalWorkspaceFromDeps( | |
| 186 | + const localScope = yield* resolveRuntimeLocalScopeFromDeps( | |
| 176 | 187 | deps, |
| 177 | − workspaceId, | |
| 188 | + scopeId, | |
| 178 | 189 | ); |
| 179 | 190 | const sources = yield* loadSourcesInWorkspaceWithDeps( |
| 180 | 191 | deps, |
| 181 | − workspaceId, | |
| 192 | + scopeId, | |
| 182 | 193 | options, |
| 183 | 194 | ); |
| 184 | 195 | const entries = yield* Effect.forEach(sources, (source) => |
| @@ -202,14 +213,14 @@ export const syncWorkspaceSourceTypeDeclarationsWithDeps = ( · 17 unmodified lines | ||
| 202 | 213 | ), |
| 203 | 214 | }); |
| 204 | 215 | }).pipe( |
| 205 | − Effect.withSpan("source.types.refresh_workspace.schedule", { | |
| 216 | + Effect.withSpan("source.types.refresh_scope.schedule", { | |
| 206 | 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 | 224 | source.enabled === false || |
| 214 | 225 | source.status === "auth_required" || |
| 215 | 226 | source.status === "error" || |
| @@ -217,24 +228,24 @@ export const shouldRefreshWorkspaceDeclarationsAfterPersist = (source: Source): · 1 unmodified line | ||
| 217 | 228 | |
| 218 | 229 | export const listLinkedSecretSourcesInWorkspaceWithDeps = ( |
| 219 | 230 | deps: RuntimeSourceStoreDeps, |
| 220 | − workspaceId: WorkspaceId, | |
| 231 | + scopeId: ScopeId, | |
| 221 | 232 | options: { |
| 222 | − actorAccountId?: AccountId | null; | |
| 233 | + actorScopeId?: ScopeId | null; | |
| 223 | 234 | } = {}, |
| 224 | 235 | ): Effect.Effect< |
| 225 | 236 | Map<string, Array<{ sourceId: string; sourceName: string }>>, |
| 226 | − | RuntimeLocalWorkspaceUnavailableError | |
| 227 | − | RuntimeLocalWorkspaceMismatchError | |
| 237 | + | RuntimeLocalScopeUnavailableError | |
| 238 | + | RuntimeLocalScopeMismatchError | |
| 228 | 239 | | LocalConfiguredSourceNotFoundError |
| 229 | 240 | | Error, |
| 230 | 241 | never |
| 231 | 242 | > => |
| 232 | 243 | Effect.gen(function* () { |
| 233 | 244 | const [sources, authArtifacts, materialIds] = yield* Effect.all([ |
| 234 | − loadSourcesInWorkspaceWithDeps(deps, workspaceId, { | |
| 235 | − actorAccountId: options.actorAccountId, | |
| 245 | + loadSourcesInWorkspaceWithDeps(deps, scopeId, { | |
| 246 | + actorScopeId: options.actorScopeId, | |
| 236 | 247 | }), |
| 237 | − deps.executorState.authArtifacts.listByWorkspaceId(workspaceId), | |
| 248 | + deps.executorState.authArtifacts.listByScopeId(scopeId), | |
| 238 | 249 | deps.executorState.secretMaterials.listAll().pipe( |
| 239 | 250 | Effect.map( |
| 240 | 251 | (materials) => new Set(materials.map((material) => String(material.id))), |
| @@ -273,39 +284,39 @@ export const listLinkedSecretSourcesInWorkspaceWithDeps = ( · 32 unmodified lines | ||
| 273 | 284 | export const loadSourceByIdWithDeps = ( |
| 274 | 285 | deps: RuntimeSourceStoreDeps, |
| 275 | 286 | input: { |
| 276 | − workspaceId: WorkspaceId; | |
| 287 | + scopeId: ScopeId; | |
| 277 | 288 | sourceId: Source["id"]; |
| 278 | − actorAccountId?: AccountId | null; | |
| 289 | + actorScopeId?: ScopeId | null; | |
| 279 | 290 | }, |
| 280 | 291 | ): Effect.Effect< |
| 281 | 292 | Source, |
| 282 | − | RuntimeLocalWorkspaceUnavailableError | |
| 283 | − | RuntimeLocalWorkspaceMismatchError | |
| 293 | + | RuntimeLocalScopeUnavailableError | |
| 294 | + | RuntimeLocalScopeMismatchError | |
| 284 | 295 | | LocalConfiguredSourceNotFoundError |
| 285 | 296 | | Error, |
| 286 | 297 | never |
| 287 | 298 | > => |
| 288 | 299 | Effect.gen(function* () { |
| 289 | − const localWorkspace = yield* resolveRuntimeLocalWorkspaceFromDeps( | |
| 300 | + const localScope = yield* resolveRuntimeLocalScopeFromDeps( | |
| 290 | 301 | deps, |
| 291 | − input.workspaceId, | |
| 302 | + input.scopeId, | |
| 292 | 303 | ); |
| 293 | − const authArtifacts = yield* deps.executorState.authArtifacts.listByWorkspaceId( | |
| 294 | − input.workspaceId, | |
| 304 | + const authArtifacts = yield* deps.executorState.authArtifacts.listByScopeId( | |
| 305 | + input.scopeId, | |
| 295 | 306 | ); |
| 296 | − if (!localWorkspace.loadedConfig.config?.sources?.[input.sourceId]) { | |
| 307 | + if (!localScope.loadedConfig.config?.sources?.[input.sourceId]) { | |
| 297 | 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 | 310 | sourceId: input.sourceId, |
| 300 | 311 | }); |
| 301 | 312 | } |
| 302 | 313 | |
| 303 | 314 | const localSource = yield* buildLocalSourceRecord({ |
| 304 | − workspaceId: input.workspaceId, | |
| 305 | − loadedConfig: localWorkspace.loadedConfig, | |
| 306 | − workspaceState: localWorkspace.workspaceState, | |
| 315 | + scopeId: input.scopeId, | |
| 316 | + loadedConfig: localScope.loadedConfig, | |
| 317 | + scopeState: localScope.scopeState, | |
| 307 | 318 | sourceId: input.sourceId, |
| 308 | − actorAccountId: input.actorAccountId, | |
| 319 | + actorScopeId: input.actorScopeId, | |
| 309 | 320 | authArtifacts, |
| 310 | 321 | }); |
| 311 | 322 | |
| @@ -313,7 +324,7 @@ export const loadSourceByIdWithDeps = ( · 1 unmodified line | ||
| 313 | 324 | }).pipe( |
| 314 | 325 | Effect.withSpan("source.store.load_by_id", { |
| 315 | 326 | attributes: { |
| 316 | − "executor.workspace.id": input.workspaceId, | |
| 327 | + "executor.scope.id": input.scopeId, | |
| 317 | 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 | 5 | export const TimestampMsSchema = Schema.Number; |
| 4 | 6 | |
| @@ -54,8 +54,8 @@ export { · 53 unmodified lines | ||
| 54 | 54 | type SourceAuthSessionStatus, |
| 55 | 55 | } from "./models/source-auth-session"; |
| 56 | 56 | export { |
| 57 | − LocalWorkspacePolicyApprovalModeSchema, | |
| 58 | − LocalWorkspacePolicyEffectSchema, | |
| 59 | − type LocalWorkspacePolicyApprovalMode, | |
| 60 | − type LocalWorkspacePolicyEffect, | |
| 57 | + LocalScopePolicyApprovalModeSchema, | |
| 58 | + LocalScopePolicyEffectSchema, | |
| 59 | + type LocalScopePolicyApprovalMode, | |
| 60 | + type LocalScopePolicyEffect, | |
| 61 | 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")); | |
| 4 | −export const WorkspaceIdSchema = Schema.String.pipe(Schema.brand("WorkspaceId")); | |
| 5 | +export const ScopeIdSchema = Schema.String.pipe(Schema.brand("ScopeId")); | |
| 5 | 6 | export const SourceIdSchema = Schema.String.pipe(Schema.brand("SourceId")); |
| 6 | 7 | export const SourceCatalogIdSchema = Schema.String.pipe(Schema.brand("SourceCatalogId")); |
| 7 | 8 | export const SourceCatalogRevisionIdSchema = Schema.String.pipe( |
| @@ -17,11 +18,11 @@ export const AuthLeaseIdSchema = Schema.String.pipe( · 9 unmodified lines | ||
| 17 | 18 | Schema.brand("AuthLeaseId"), |
| 18 | 19 | ); |
| 19 | 20 | export const CredentialIdSchema = AuthArtifactIdSchema; |
| 20 | −export const WorkspaceSourceOauthClientIdSchema = Schema.String.pipe( | |
| 21 | − Schema.brand("WorkspaceSourceOauthClientId"), | |
| 21 | +export const ScopedSourceOauthClientIdSchema = Schema.String.pipe( | |
| 22 | + Schema.brand("ScopedSourceOauthClientId"), | |
| 22 | 23 | ); |
| 23 | −export const WorkspaceOauthClientIdSchema = Schema.String.pipe( | |
| 24 | − Schema.brand("WorkspaceOauthClientId"), | |
| 24 | +export const ScopeOauthClientIdSchema = Schema.String.pipe( | |
| 25 | + Schema.brand("ScopeOauthClientId"), | |
| 25 | 26 | ); |
| 26 | 27 | export const ProviderAuthGrantIdSchema = Schema.String.pipe( |
| 27 | 28 | Schema.brand("ProviderAuthGrantId"), |
| @@ -38,8 +39,7 @@ export const ExecutionStepIdSchema = Schema.String.pipe( · 10 unmodified lines | ||
| 38 | 39 | Schema.brand("ExecutionStepId"), |
| 39 | 40 | ); |
| 40 | 41 | |
| 41 | −export type AccountId = typeof AccountIdSchema.Type; | |
| 42 | −export type WorkspaceId = typeof WorkspaceIdSchema.Type; | |
| 42 | +export type ScopeId = typeof ScopeIdSchema.Type; | |
| 43 | 43 | export type SourceId = typeof SourceIdSchema.Type; |
| 44 | 44 | export type SourceCatalogId = typeof SourceCatalogIdSchema.Type; |
| 45 | 45 | export type SourceCatalogRevisionId = typeof SourceCatalogRevisionIdSchema.Type; |
| @@ -47,8 +47,8 @@ export type SourceAuthSessionId = typeof SourceAuthSessionIdSchema.Type; · 1 unmodified line | ||
| 47 | 47 | export type AuthArtifactId = typeof AuthArtifactIdSchema.Type; |
| 48 | 48 | export type AuthLeaseId = typeof AuthLeaseIdSchema.Type; |
| 49 | 49 | export type CredentialId = typeof CredentialIdSchema.Type; |
| 50 | −export type WorkspaceSourceOauthClientId = typeof WorkspaceSourceOauthClientIdSchema.Type; | |
| 51 | −export type WorkspaceOauthClientId = typeof WorkspaceOauthClientIdSchema.Type; | |
| 50 | +export type ScopedSourceOauthClientId = typeof ScopedSourceOauthClientIdSchema.Type; | |
| 51 | +export type ScopeOauthClientId = typeof ScopeOauthClientIdSchema.Type; | |
| 52 | 52 | export type ProviderAuthGrantId = typeof ProviderAuthGrantIdSchema.Type; |
| 53 | 53 | export type SecretMaterialId = typeof SecretMaterialIdSchema.Type; |
| 54 | 54 | export type PolicyId = typeof PolicyIdSchema.Type; |
| @@ -7,7 +7,7 @@ export * from "./models/source-catalog"; · 6 unmodified lines | ||
| 7 | 7 | export * from "./models/auth-artifact"; |
| 8 | 8 | export * from "./models/auth-lease"; |
| 9 | 9 | export * from "./models/source-oauth-client"; |
| 10 | −export * from "./models/workspace-oauth-client"; | |
| 10 | +export * from "./models/scope-oauth-client"; | |
| 11 | 11 | export * from "./models/provider-auth-grant"; |
| 12 | 12 | export * from "./models/secret-material"; |
| 13 | 13 | export * from "./models/source-auth-session"; |
| @@ -1,13 +1,16 @@ | ||
| 1 | −import { Schema } from "effect"; | |
| 1 | +import { | |
| 2 | + Schema, | |
| 3 | +} from "effect"; | |
| 2 | 4 | import * as Option from "effect/Option"; |
| 3 | 5 | |
| 4 | −import { TimestampMsSchema } from "../common"; | |
| 5 | 6 | import { |
| 6 | − AccountIdSchema, | |
| 7 | + TimestampMsSchema, | |
| 8 | +} from "../common"; | |
| 9 | +import { | |
| 10 | + ScopeIdSchema, | |
| 7 | 11 | AuthArtifactIdSchema, |
| 8 | 12 | ProviderAuthGrantIdSchema, |
| 9 | 13 | SourceIdSchema, |
| 10 | − WorkspaceIdSchema, | |
| 11 | 14 | } from "../ids"; |
| 12 | 15 | |
| 13 | 16 | export const SecretRefSchema = Schema.Struct({ |
| @@ -207,9 +210,9 @@ const decodeAuthGrantSetOption = Schema.decodeUnknownOption(AuthGrantSetJsonSche · 193 unmodified lines | ||
| 207 | 210 | |
| 208 | 211 | export const AuthArtifactSchema = Schema.Struct({ |
| 209 | 212 | id: AuthArtifactIdSchema, |
| 210 | − workspaceId: WorkspaceIdSchema, | |
| 213 | + scopeId: ScopeIdSchema, | |
| 211 | 214 | sourceId: SourceIdSchema, |
| 212 | − actorAccountId: Schema.NullOr(AccountIdSchema), | |
| 215 | + actorScopeId: Schema.NullOr(ScopeIdSchema), | |
| 213 | 216 | slot: AuthArtifactSlotSchema, |
| 214 | 217 | artifactKind: AuthArtifactKindSchema, |
| 215 | 218 | configJson: Schema.String, |
| @@ -1,13 +1,16 @@ | ||
| 1 | −import { Schema } from "effect"; | |
| 1 | +import { | |
| 2 | + Schema, | |
| 3 | +} from "effect"; | |
| 2 | 4 | import * as Option from "effect/Option"; |
| 3 | 5 | |
| 4 | −import { TimestampMsSchema } from "../common"; | |
| 5 | 6 | import { |
| 6 | − AccountIdSchema, | |
| 7 | + TimestampMsSchema, | |
| 8 | +} from "../common"; | |
| 9 | +import { | |
| 10 | + ScopeIdSchema, | |
| 7 | 11 | AuthArtifactIdSchema, |
| 8 | 12 | AuthLeaseIdSchema, |
| 9 | 13 | SourceIdSchema, |
| 10 | − WorkspaceIdSchema, | |
| 11 | 14 | } from "../ids"; |
| 12 | 15 | |
| 13 | 16 | import { |
| @@ -19,9 +22,9 @@ import { · 5 unmodified lines | ||
| 19 | 22 | export const AuthLeaseSchema = Schema.Struct({ |
| 20 | 23 | id: AuthLeaseIdSchema, |
| 21 | 24 | authArtifactId: AuthArtifactIdSchema, |
| 22 | − workspaceId: WorkspaceIdSchema, | |
| 25 | + scopeId: ScopeIdSchema, | |
| 23 | 26 | sourceId: SourceIdSchema, |
| 24 | − actorAccountId: Schema.NullOr(AccountIdSchema), | |
| 27 | + actorScopeId: Schema.NullOr(ScopeIdSchema), | |
| 25 | 28 | slot: AuthArtifactSlotSchema, |
| 26 | 29 | placementsTemplateJson: Schema.String, |
| 27 | 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 | 9 | export const StoredCodeMigrationRecordSchema = Schema.Struct({ |
| 6 | 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 | 5 | import { |
| 5 | − AccountIdSchema, | |
| 6 | + TimestampMsSchema, | |
| 7 | +} from "../common"; | |
| 8 | +import { | |
| 6 | 9 | ExecutionIdSchema, |
| 7 | 10 | ExecutionInteractionIdSchema, |
| 8 | 11 | ExecutionStepIdSchema, |
| 9 | − WorkspaceIdSchema, | |
| 12 | + ScopeIdSchema, | |
| 10 | 13 | } from "../ids"; |
| 11 | 14 | |
| 12 | 15 | export const ExecutionStatusSchema = Schema.Literal( |
| @@ -20,8 +23,8 @@ export const ExecutionStatusSchema = Schema.Literal( · 7 unmodified lines | ||
| 20 | 23 | |
| 21 | 24 | export const ExecutionSchema = Schema.Struct({ |
| 22 | 25 | id: ExecutionIdSchema, |
| 23 | − workspaceId: WorkspaceIdSchema, | |
| 24 | − createdByAccountId: AccountIdSchema, | |
| 26 | + scopeId: ScopeIdSchema, | |
| 27 | + createdByScopeId: ScopeIdSchema, | |
| 25 | 28 | status: ExecutionStatusSchema, |
| 26 | 29 | code: Schema.String, |
| 27 | 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 | 9 | export const LocalExecutorRuntimeSchema = Schema.Literal( |
| 6 | 10 | "quickjs", |
| @@ -1,13 +1,13 @@ | ||
| 1 | 1 | import * as Schema from "effect/Schema"; |
| 2 | 2 | |
| 3 | 3 | import { |
| 4 | − AccountIdSchema, | |
| 5 | − WorkspaceIdSchema, | |
| 4 | + ScopeIdSchema, | |
| 6 | 5 | } from "../ids"; |
| 7 | 6 | |
| 8 | 7 | export const LocalInstallationSchema = Schema.Struct({ |
| 9 | − accountId: AccountIdSchema, | |
| 10 | − workspaceId: WorkspaceIdSchema, | |
| 8 | + scopeId: ScopeIdSchema, | |
| 9 | + actorScopeId: ScopeIdSchema, | |
| 10 | + resolutionScopeIds: Schema.Array(ScopeIdSchema), | |
| 11 | 11 | }); |
| 12 | 12 | |
| 13 | 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"; | |
| 4 | −import { PolicyIdSchema, WorkspaceIdSchema } from "../ids"; | |
| 5 | +import { | |
| 6 | + TimestampMsSchema, | |
| 7 | +} from "../common"; | |
| 8 | +import { | |
| 9 | + PolicyIdSchema, | |
| 10 | + ScopeIdSchema, | |
| 11 | +} from "../ids"; | |
| 5 | 12 | |
| 6 | −export const LocalWorkspacePolicyEffectSchema = Schema.Literal("allow", "deny"); | |
| 7 | −export const LocalWorkspacePolicyApprovalModeSchema = Schema.Literal("auto", "required"); | |
| 13 | +export const LocalScopePolicyEffectSchema = Schema.Literal("allow", "deny"); | |
| 14 | +export const LocalScopePolicyApprovalModeSchema = Schema.Literal("auto", "required"); | |
| 8 | 15 | |
| 9 | −export const LocalWorkspacePolicySchema = Schema.Struct({ | |
| 16 | +export const LocalScopePolicySchema = Schema.Struct({ | |
| 10 | 17 | id: PolicyIdSchema, |
| 11 | 18 | key: Schema.String, |
| 12 | − workspaceId: WorkspaceIdSchema, | |
| 19 | + scopeId: ScopeIdSchema, | |
| 13 | 20 | resourcePattern: Schema.String, |
| 14 | − effect: LocalWorkspacePolicyEffectSchema, | |
| 15 | − approvalMode: LocalWorkspacePolicyApprovalModeSchema, | |
| 21 | + effect: LocalScopePolicyEffectSchema, | |
| 22 | + approvalMode: LocalScopePolicyApprovalModeSchema, | |
| 16 | 23 | priority: Schema.Number, |
| 17 | 24 | enabled: Schema.Boolean, |
| 18 | 25 | createdAt: TimestampMsSchema, |
| 19 | 26 | updatedAt: TimestampMsSchema, |
| 20 | 27 | }); |
| 21 | 28 | |
| 22 | −export const LocalWorkspacePolicyInsertSchema = LocalWorkspacePolicySchema; | |
| 23 | −export const LocalWorkspacePolicyUpdateSchema = Schema.partial(LocalWorkspacePolicySchema); | |
| 29 | +export const LocalScopePolicyInsertSchema = LocalScopePolicySchema; | |
| 30 | +export const LocalScopePolicyUpdateSchema = Schema.partial(LocalScopePolicySchema); | |
| 24 | 31 | |
| 25 | −export type LocalWorkspacePolicyEffect = typeof LocalWorkspacePolicyEffectSchema.Type; | |
| 26 | −export type LocalWorkspacePolicyApprovalMode = | |
| 27 | − typeof LocalWorkspacePolicyApprovalModeSchema.Type; | |
| 28 | −export type LocalWorkspacePolicy = typeof LocalWorkspacePolicySchema.Type; | |
| 32 | +export type LocalScopePolicyEffect = typeof LocalScopePolicyEffectSchema.Type; | |
| 33 | +export type LocalScopePolicyApprovalMode = | |
| 34 | + typeof LocalScopePolicyApprovalModeSchema.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 | 5 | import { |
| 5 | − AccountIdSchema, | |
| 6 | + TimestampMsSchema, | |
| 7 | +} from "../common"; | |
| 8 | +import { | |
| 9 | + ScopeIdSchema, | |
| 6 | 10 | ProviderAuthGrantIdSchema, |
| 7 | − WorkspaceIdSchema, | |
| 8 | − WorkspaceOauthClientIdSchema, | |
| 11 | + ScopeOauthClientIdSchema, | |
| 9 | 12 | } from "../ids"; |
| 10 | 13 | |
| 11 | 14 | import { |
| @@ -15,10 +18,10 @@ import { · 3 unmodified lines | ||
| 15 | 18 | |
| 16 | 19 | export const ProviderAuthGrantSchema = Schema.Struct({ |
| 17 | 20 | id: ProviderAuthGrantIdSchema, |
| 18 | − workspaceId: WorkspaceIdSchema, | |
| 19 | − actorAccountId: Schema.NullOr(AccountIdSchema), | |
| 21 | + scopeId: ScopeIdSchema, | |
| 22 | + actorScopeId: Schema.NullOr(ScopeIdSchema), | |
| 20 | 23 | providerKey: Schema.String, |
| 21 | − oauthClientId: WorkspaceOauthClientIdSchema, | |
| 24 | + oauthClientId: ScopeOauthClientIdSchema, | |
| 22 | 25 | tokenEndpoint: Schema.String, |
| 23 | 26 | clientAuthentication: OAuth2ClientAuthenticationMethodSchema, |
| 24 | 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 | 5 | import { |
| 5 | − WorkspaceIdSchema, | |
| 6 | − WorkspaceOauthClientIdSchema, | |
| 6 | + TimestampMsSchema, | |
| 7 | +} from "../common"; | |
| 8 | +import { | |
| 9 | + ScopeIdSchema, | |
| 10 | + ScopeOauthClientIdSchema, | |
| 7 | 11 | } from "../ids"; |
| 8 | 12 | |
| 9 | −export const WorkspaceOauthClientSchema = Schema.Struct({ | |
| 10 | − id: WorkspaceOauthClientIdSchema, | |
| 11 | − workspaceId: WorkspaceIdSchema, | |
| 13 | +export const ScopeOauthClientSchema = Schema.Struct({ | |
| 14 | + id: ScopeOauthClientIdSchema, | |
| 15 | + scopeId: ScopeIdSchema, | |
| 12 | 16 | providerKey: Schema.String, |
| 13 | 17 | label: Schema.NullOr(Schema.String), |
| 14 | 18 | clientId: Schema.String, |
| @@ -19,4 +23,4 @@ export const WorkspaceOauthClientSchema = Schema.Struct({ · 4 unmodified lines | ||
| 19 | 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"; | |
| 4 | −import { SecretMaterialIdSchema } from "../ids"; | |
| 5 | +import { | |
| 6 | + TimestampMsSchema, | |
| 7 | +} from "../common"; | |
| 8 | +import { | |
| 9 | + SecretMaterialIdSchema, | |
| 10 | +} from "../ids"; | |
| 5 | 11 | |
| 6 | 12 | export const SecretMaterialPurposeSchema = Schema.Literal( |
| 7 | 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 | 5 | import { |
| 5 | − AccountIdSchema, | |
| 6 | + TimestampMsSchema, | |
| 7 | +} from "../common"; | |
| 8 | +import { | |
| 9 | + ScopeIdSchema, | |
| 6 | 10 | ExecutionIdSchema, |
| 7 | 11 | ExecutionInteractionIdSchema, |
| 8 | 12 | SourceIdSchema, |
| 9 | 13 | SourceAuthSessionIdSchema, |
| 10 | − WorkspaceOauthClientIdSchema, | |
| 11 | − WorkspaceIdSchema, | |
| 14 | + ScopeOauthClientIdSchema, | |
| 12 | 15 | } from "../ids"; |
| 13 | 16 | import { |
| 14 | 17 | CredentialSlotSchema, |
| @@ -109,7 +112,7 @@ export const ProviderOauthBatchSourceAuthSessionDataSchema = Schema.Struct({ · 94 unmodified lines | ||
| 109 | 112 | authorizationEndpoint: Schema.String, |
| 110 | 113 | tokenEndpoint: Schema.String, |
| 111 | 114 | redirectUri: Schema.String, |
| 112 | − oauthClientId: WorkspaceOauthClientIdSchema, | |
| 115 | + oauthClientId: ScopeOauthClientIdSchema, | |
| 113 | 116 | clientAuthentication: OAuth2ClientAuthenticationMethodSchema, |
| 114 | 117 | scopes: Schema.Array(Schema.String), |
| 115 | 118 | headerName: Schema.String, |
| @@ -129,9 +132,9 @@ export const ProviderOauthBatchSourceAuthSessionDataJsonSchema = Schema.parseJso · 13 unmodified lines | ||
| 129 | 132 | |
| 130 | 133 | export const SourceAuthSessionSchema = Schema.Struct({ |
| 131 | 134 | id: SourceAuthSessionIdSchema, |
| 132 | − workspaceId: WorkspaceIdSchema, | |
| 135 | + scopeId: ScopeIdSchema, | |
| 133 | 136 | sourceId: SourceIdSchema, |
| 134 | − actorAccountId: Schema.NullOr(AccountIdSchema), | |
| 137 | + actorScopeId: Schema.NullOr(ScopeIdSchema), | |
| 135 | 138 | credentialSlot: CredentialSlotSchema, |
| 136 | 139 | executionId: Schema.NullOr(ExecutionIdSchema), |
| 137 | 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 | 8 | import { |
| 5 | 9 | SourceCatalogIdSchema, |
| 6 | 10 | SourceCatalogRevisionIdSchema, |
| @@ -15,7 +19,7 @@ export const SourceCatalogAdapterKeySchema = Schema.String; · 8 unmodified lines | ||
| 15 | 19 | |
| 16 | 20 | export const SourceCatalogVisibilitySchema = Schema.Literal( |
| 17 | 21 | "private", |
| 18 | − "workspace", | |
| 22 | + "scope", | |
| 19 | 23 | "organization", |
| 20 | 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 | 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 | 4 | export { |
| 3 | 5 | SourceOauthClientInputSchema, |
| 4 | − WorkspaceSourceOauthClientRedirectModeSchema, | |
| 6 | + ScopedSourceOauthClientRedirectModeSchema, | |
| 5 | 7 | } from "@executor/source-core"; |
| 6 | 8 | import { |
| 7 | 9 | SourceOauthClientInputSchema, |
| 8 | − WorkspaceSourceOauthClientRedirectModeSchema, | |
| 10 | + ScopedSourceOauthClientRedirectModeSchema, | |
| 9 | 11 | } from "@executor/source-core"; |
| 10 | 12 | |
| 11 | −import { TimestampMsSchema } from "../common"; | |
| 13 | +import { | |
| 14 | + TimestampMsSchema, | |
| 15 | +} from "../common"; | |
| 12 | 16 | import { |
| 13 | 17 | SourceIdSchema, |
| 14 | − WorkspaceIdSchema, | |
| 15 | − WorkspaceSourceOauthClientIdSchema, | |
| 18 | + ScopeIdSchema, | |
| 19 | + ScopedSourceOauthClientIdSchema, | |
| 16 | 20 | } from "../ids"; |
| 17 | 21 | |
| 18 | −export const WorkspaceSourceOauthClientMetadataSchema = Schema.Struct({ | |
| 19 | − redirectMode: Schema.optional(WorkspaceSourceOauthClientRedirectModeSchema), | |
| 22 | +export const ScopedSourceOauthClientMetadataSchema = Schema.Struct({ | |
| 23 | + redirectMode: Schema.optional(ScopedSourceOauthClientRedirectModeSchema), | |
| 20 | 24 | }); |
| 21 | 25 | |
| 22 | −export const WorkspaceSourceOauthClientMetadataJsonSchema = Schema.parseJson( | |
| 23 | − WorkspaceSourceOauthClientMetadataSchema, | |
| 26 | +export const ScopedSourceOauthClientMetadataJsonSchema = Schema.parseJson( | |
| 27 | + ScopedSourceOauthClientMetadataSchema, | |
| 24 | 28 | ); |
| 25 | 29 | |
| 26 | −export const WorkspaceSourceOauthClientSchema = Schema.Struct({ | |
| 27 | − id: WorkspaceSourceOauthClientIdSchema, | |
| 28 | − workspaceId: WorkspaceIdSchema, | |
| 30 | +export const ScopedSourceOauthClientSchema = Schema.Struct({ | |
| 31 | + id: ScopedSourceOauthClientIdSchema, | |
| 32 | + scopeId: ScopeIdSchema, | |
| 29 | 33 | sourceId: SourceIdSchema, |
| 30 | 34 | providerKey: Schema.String, |
| 31 | 35 | clientId: Schema.String, |
| @@ -36,9 +40,9 @@ export const WorkspaceSourceOauthClientSchema = Schema.Struct({ · 4 unmodified lines | ||
| 36 | 40 | updatedAt: TimestampMsSchema, |
| 37 | 41 | }); |
| 38 | 42 | |
| 39 | −export type WorkspaceSourceOauthClient = typeof WorkspaceSourceOauthClientSchema.Type; | |
| 40 | −export type WorkspaceSourceOauthClientRedirectMode = | |
| 41 | − typeof WorkspaceSourceOauthClientRedirectModeSchema.Type; | |
| 42 | −export type WorkspaceSourceOauthClientMetadata = | |
| 43 | − typeof WorkspaceSourceOauthClientMetadataSchema.Type; | |
| 43 | +export type ScopedSourceOauthClient = typeof ScopedSourceOauthClientSchema.Type; | |
| 44 | +export type ScopedSourceOauthClientRedirectMode = | |
| 45 | + typeof ScopedSourceOauthClientRedirectModeSchema.Type; | |
| 46 | +export type ScopedSourceOauthClientMetadata = | |
| 47 | + typeof ScopedSourceOauthClientMetadataSchema.Type; | |
| 44 | 48 | export type SourceOauthClientInput = typeof SourceOauthClientInputSchema.Type; |
| @@ -1,4 +1,6 @@ | ||
| 1 | −import { Schema } from "effect"; | |
| 1 | +import { | |
| 2 | + Schema, | |
| 3 | +} from "effect"; | |
| 2 | 4 | export { |
| 3 | 5 | SourceImportAuthPolicySchema, |
| 4 | 6 | SourceTransportSchema, |
| @@ -10,16 +12,22 @@ import { · 5 unmodified lines | ||
| 10 | 12 | StringMapSchema, |
| 11 | 13 | } from "@executor/source-core"; |
| 12 | 14 | |
| 13 | −import { TimestampMsSchema } from "../common"; | |
| 15 | +import { | |
| 16 | + TimestampMsSchema, | |
| 17 | +} from "../common"; | |
| 14 | 18 | import { |
| 15 | 19 | ProviderAuthGrantIdSchema, |
| 16 | 20 | SourceIdSchema, |
| 17 | 21 | SourceCatalogIdSchema, |
| 18 | 22 | SourceCatalogRevisionIdSchema, |
| 19 | − WorkspaceIdSchema, | |
| 23 | + ScopeIdSchema, | |
| 20 | 24 | } from "../ids"; |
| 21 | −import { SecretRefSchema } from "./auth-artifact"; | |
| 22 | −import { JsonObjectSchema } from "./source-auth-session"; | |
| 25 | +import { | |
| 26 | + SecretRefSchema, | |
| 27 | +} from "./auth-artifact"; | |
| 28 | +import { | |
| 29 | + JsonObjectSchema, | |
| 30 | +} from "./source-auth-session"; | |
| 23 | 31 | |
| 24 | 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 | 101 | const SourceStorageRowSchema = Schema.Struct({ |
| 94 | − workspaceId: WorkspaceIdSchema, | |
| 102 | + scopeId: ScopeIdSchema, | |
| 95 | 103 | sourceId: SourceIdSchema, |
| 96 | 104 | catalogId: SourceCatalogIdSchema, |
| 97 | 105 | catalogRevisionId: SourceCatalogRevisionIdSchema, |
| @@ -113,7 +121,7 @@ export const StoredSourceRecordSchema = Schema.transform( · 15 unmodified lines | ||
| 113 | 121 | SourceStorageRowSchema, |
| 114 | 122 | Schema.Struct({ |
| 115 | 123 | id: SourceIdSchema, |
| 116 | − workspaceId: WorkspaceIdSchema, | |
| 124 | + scopeId: ScopeIdSchema, | |
| 117 | 125 | catalogId: SourceCatalogIdSchema, |
| 118 | 126 | catalogRevisionId: SourceCatalogRevisionIdSchema, |
| 119 | 127 | name: Schema.String, |
| @@ -133,7 +141,7 @@ export const StoredSourceRecordSchema = Schema.transform( · 13 unmodified lines | ||
| 133 | 141 | strict: false, |
| 134 | 142 | decode: (row) => ({ |
| 135 | 143 | id: row.sourceId, |
| 136 | − workspaceId: row.workspaceId, | |
| 144 | + scopeId: row.scopeId, | |
| 137 | 145 | catalogId: row.catalogId, |
| 138 | 146 | catalogRevisionId: row.catalogRevisionId, |
| 139 | 147 | name: row.name, |
| @@ -150,7 +158,7 @@ export const StoredSourceRecordSchema = Schema.transform( · 10 unmodified lines | ||
| 150 | 158 | updatedAt: row.updatedAt, |
| 151 | 159 | }), |
| 152 | 160 | encode: (source) => ({ |
| 153 | − workspaceId: source.workspaceId, | |
| 161 | + scopeId: source.scopeId, | |
| 154 | 162 | sourceId: source.id, |
| 155 | 163 | catalogId: source.catalogId, |
| 156 | 164 | catalogRevisionId: source.catalogRevisionId, |
| @@ -172,7 +180,7 @@ export const StoredSourceRecordSchema = Schema.transform( · 15 unmodified lines | ||
| 172 | 180 | |
| 173 | 181 | export const SourceSchema = Schema.Struct({ |
| 174 | 182 | id: SourceIdSchema, |
| 175 | − workspaceId: WorkspaceIdSchema, | |
| 183 | + scopeId: ScopeIdSchema, | |
| 176 | 184 | name: Schema.String, |
| 177 | 185 | kind: SourceKindSchema, |
| 178 | 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 | 6 | import * as Either from "effect/Either"; |
| 3 | 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 | 12 | SourceSchema, |
| 13 | 13 | SourceStatusSchema, |
| 14 | 14 | SourceOauthClientInputSchema, |
| 15 | − WorkspaceIdSchema, | |
| 16 | − WorkspaceOauthClientIdSchema, | |
| 17 | − WorkspaceOauthClientSchema, | |
| 15 | + ScopeIdSchema, | |
| 16 | + ScopeOauthClientIdSchema, | |
| 17 | + ScopeOauthClientSchema, | |
| 18 | 18 | } from "../schema"; |
| 19 | 19 | import { |
| 20 | 20 | ConnectSourcePayloadSchema, |
| @@ -84,20 +84,20 @@ export const CredentialOauthCompleteUrlParamsSchema = Schema.Struct({ · 63 unmodified lines | ||
| 84 | 84 | error_description: Schema.optional(Schema.String), |
| 85 | 85 | }); |
| 86 | 86 | |
| 87 | −export const WorkspaceOauthClientQuerySchema = Schema.Struct({ | |
| 87 | +export const ScopeOauthClientQuerySchema = Schema.Struct({ | |
| 88 | 88 | providerKey: Schema.String, |
| 89 | 89 | }); |
| 90 | 90 | |
| 91 | −export const CreateWorkspaceOauthClientPayloadSchema = Schema.Struct({ | |
| 91 | +export const CreateScopeOauthClientPayloadSchema = Schema.Struct({ | |
| 92 | 92 | providerKey: Schema.String, |
| 93 | 93 | label: Schema.optional(Schema.NullOr(Schema.String)), |
| 94 | 94 | oauthClient: SourceOauthClientInputSchema, |
| 95 | 95 | }); |
| 96 | 96 | |
| 97 | −export type CreateWorkspaceOauthClientPayload = | |
| 98 | − typeof CreateWorkspaceOauthClientPayloadSchema.Type; | |
| 97 | +export type CreateScopeOauthClientPayload = | |
| 98 | + typeof CreateScopeOauthClientPayloadSchema.Type; | |
| 99 | 99 | |
| 100 | −export const oauthClientIdParam = WorkspaceOauthClientIdSchema; | |
| 100 | +export const oauthClientIdParam = ScopeOauthClientIdSchema; | |
| 101 | 101 | export const grantIdParam = ProviderAuthGrantIdSchema; |
| 102 | 102 | |
| 103 | 103 | const ConnectGoogleDiscoveryBatchSourceSchema = Schema.Struct({ |
| @@ -110,7 +110,7 @@ const ConnectGoogleDiscoveryBatchSourceSchema = Schema.Struct({ · 6 unmodified lines | ||
| 110 | 110 | }); |
| 111 | 111 | |
| 112 | 112 | export const ConnectSourceBatchPayloadSchema = Schema.Struct({ |
| 113 | − workspaceOauthClientId: WorkspaceOauthClientIdSchema, | |
| 113 | + scopeOauthClientId: ScopeOauthClientIdSchema, | |
| 114 | 114 | sources: Schema.Array(ConnectGoogleDiscoveryBatchSourceSchema), |
| 115 | 115 | }); |
| 116 | 116 | |
| @@ -165,6 +165,6 @@ export { · 48 unmodified lines | ||
| 165 | 165 | ConnectSourcePayloadSchema, |
| 166 | 166 | type ConnectSourcePayload, |
| 167 | 167 | SourceDiscoveryResultSchema, |
| 168 | − WorkspaceIdSchema, | |
| 169 | − WorkspaceOauthClientSchema, | |
| 168 | + ScopeIdSchema, | |
| 169 | + ScopeOauthClientSchema, | |
| 170 | 170 | }; |
| @@ -9,7 +9,9 @@ import { · 8 unmodified lines | ||
| 9 | 9 | type SourceDiscoveryResult, |
| 10 | 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 | 16 | type DiscoverableSourceAdapter = SourceAdapter & { |
| 15 | 17 | detectSource: NonNullable<SourceAdapter["detectSource"]>; |
| @@ -8,7 +8,7 @@ import type { · 7 unmodified lines | ||
| 8 | 8 | SourceInspectionToolDetail, |
| 9 | 9 | SourceInspectionToolListItem, |
| 10 | 10 | SourceInspectionToolSummary, |
| 11 | − WorkspaceId, | |
| 11 | + ScopeId, | |
| 12 | 12 | } from "../schema"; |
| 13 | 13 | import { |
| 14 | 14 | ControlPlaneNotFoundError, |
| @@ -16,8 +16,12 @@ import { · 1 unmodified line | ||
| 16 | 16 | } from "../errors"; |
| 17 | 17 | import * as Effect from "effect/Effect"; |
| 18 | 18 | |
| 19 | −import { LocalSourceArtifactMissingError } from "../runtime/workspace-errors"; | |
| 20 | −import { operationErrors } from "../runtime/policy/operation-errors"; | |
| 19 | +import { | |
| 20 | + LocalSourceArtifactMissingError, | |
| 21 | +} from "../runtime/scope-errors"; | |
| 22 | +import { | |
| 23 | + operationErrors, | |
| 24 | +} from "../runtime/policy/operation-errors"; | |
| 21 | 25 | import { |
| 22 | 26 | buildLoadedSourceCatalogToolContract, |
| 23 | 27 | expandCatalogToolByPath, |
| @@ -25,7 +29,9 @@ import { · 1 unmodified line | ||
| 25 | 29 | loadSourceWithCatalog, |
| 26 | 30 | type LoadedSourceCatalogTool, |
| 27 | 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 | 36 | const sourceInspectOps = { |
| 31 | 37 | bundle: operationErrors("sources.inspect.bundle"), |
| @@ -46,14 +52,14 @@ const canInspectSourceWithoutCatalog = (source: Source): boolean => · 14 unmodified lines | ||
| 46 | 52 | source.status === "auth_required"; |
| 47 | 53 | |
| 48 | 54 | const loadSourceForMissingCatalog = (input: { |
| 49 | − workspaceId: WorkspaceId; | |
| 55 | + scopeId: ScopeId; | |
| 50 | 56 | sourceId: SourceId; |
| 51 | 57 | cause: LocalSourceArtifactMissingError; |
| 52 | 58 | }) => |
| 53 | 59 | Effect.gen(function* () { |
| 54 | 60 | const sourceStore = yield* RuntimeSourceStoreService; |
| 55 | 61 | const source = yield* sourceStore.loadSourceById({ |
| 56 | − workspaceId: input.workspaceId, | |
| 62 | + scopeId: input.scopeId, | |
| 57 | 63 | sourceId: input.sourceId, |
| 58 | 64 | }); |
| 59 | 65 | |
| @@ -65,11 +71,11 @@ const loadSourceForMissingCatalog = (input: { · 5 unmodified lines | ||
| 65 | 71 | }); |
| 66 | 72 | |
| 67 | 73 | const loadSourceCatalogOrEmpty = (input: { |
| 68 | − workspaceId: WorkspaceId; | |
| 74 | + scopeId: ScopeId; | |
| 69 | 75 | sourceId: SourceId; |
| 70 | 76 | }) => |
| 71 | 77 | loadSourceWithCatalog({ |
| 72 | − workspaceId: input.workspaceId, | |
| 78 | + scopeId: input.scopeId, | |
| 73 | 79 | sourceId: input.sourceId, |
| 74 | 80 | }).pipe( |
| 75 | 81 | Effect.map((catalogEntry) => ({ |
| @@ -79,7 +85,7 @@ const loadSourceCatalogOrEmpty = (input: { · 3 unmodified lines | ||
| 79 | 85 | Effect.catchTag("LocalSourceArtifactMissingError", (cause) => |
| 80 | 86 | Effect.gen(function* () { |
| 81 | 87 | const source = yield* loadSourceForMissingCatalog({ |
| 82 | − workspaceId: input.workspaceId, | |
| 88 | + scopeId: input.scopeId, | |
| 83 | 89 | sourceId: input.sourceId, |
| 84 | 90 | cause, |
| 85 | 91 | }); |
| @@ -273,14 +279,14 @@ export const inspectionToolDetailFromTool = ( · 187 unmodified lines | ||
| 273 | 279 | }); |
| 274 | 280 | |
| 275 | 281 | const resolveSourceInspection = (input: { |
| 276 | − workspaceId: WorkspaceId; | |
| 282 | + scopeId: ScopeId; | |
| 277 | 283 | sourceId: SourceId; |
| 278 | 284 | includeSchemas: boolean; |
| 279 | 285 | includeTypePreviews: boolean; |
| 280 | 286 | }) => |
| 281 | 287 | Effect.gen(function* () { |
| 282 | 288 | const loaded = yield* loadSourceCatalogOrEmpty({ |
| 283 | − workspaceId: input.workspaceId, | |
| 289 | + scopeId: input.scopeId, | |
| 284 | 290 | sourceId: input.sourceId, |
| 285 | 291 | }); |
| 286 | 292 | |
| @@ -308,13 +314,13 @@ const resolveSourceInspection = (input: { · 21 unmodified lines | ||
| 308 | 314 | }); |
| 309 | 315 | |
| 310 | 316 | const resolveSourceInspectionTool = (input: { |
| 311 | − workspaceId: WorkspaceId; | |
| 317 | + scopeId: ScopeId; | |
| 312 | 318 | sourceId: SourceId; |
| 313 | 319 | toolPath: string; |
| 314 | 320 | }) => |
| 315 | 321 | Effect.gen(function* () { |
| 316 | 322 | const loaded = yield* loadSourceCatalogOrEmpty({ |
| 317 | − workspaceId: input.workspaceId, | |
| 323 | + scopeId: input.scopeId, | |
| 318 | 324 | sourceId: input.sourceId, |
| 319 | 325 | }); |
| 320 | 326 | |
| @@ -425,7 +431,7 @@ const mapInspectionError = ( · 104 unmodified lines | ||
| 425 | 431 | }; |
| 426 | 432 | |
| 427 | 433 | export const getSourceInspection = (input: { |
| 428 | − workspaceId: WorkspaceId; | |
| 434 | + scopeId: ScopeId; | |
| 429 | 435 | sourceId: SourceId; |
| 430 | 436 | }) => |
| 431 | 437 | Effect.gen(function* () { |
| @@ -456,13 +462,13 @@ export const getSourceInspection = (input: { · 24 unmodified lines | ||
| 456 | 462 | ); |
| 457 | 463 | |
| 458 | 464 | export const getSourceInspectionToolDetail = (input: { |
| 459 | − workspaceId: WorkspaceId; | |
| 465 | + scopeId: ScopeId; | |
| 460 | 466 | sourceId: SourceId; |
| 461 | 467 | toolPath: string; |
| 462 | 468 | }) => |
| 463 | 469 | Effect.gen(function* () { |
| 464 | 470 | const inspection = yield* resolveSourceInspectionTool({ |
| 465 | − workspaceId: input.workspaceId, | |
| 471 | + scopeId: input.scopeId, | |
| 466 | 472 | sourceId: input.sourceId, |
| 467 | 473 | toolPath: input.toolPath, |
| 468 | 474 | }); |
| @@ -471,7 +477,7 @@ export const getSourceInspectionToolDetail = (input: { · 2 unmodified lines | ||
| 471 | 477 | if (!tool) { |
| 472 | 478 | return yield* sourceInspectOps.tool.notFound( |
| 473 | 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 | 495 | export const discoverSourceInspectionTools = (input: { |
| 490 | − workspaceId: WorkspaceId; | |
| 496 | + scopeId: ScopeId; | |
| 491 | 497 | sourceId: SourceId; |
| 492 | 498 | payload: SourceInspectionDiscoverPayload; |
| 493 | 499 | }) => |
| 494 | 500 | Effect.gen(function* () { |
| 495 | 501 | const inspection = yield* resolveSourceInspection({ |
| 496 | − workspaceId: input.workspaceId, | |
| 502 | + scopeId: input.scopeId, | |
| 497 | 503 | sourceId: input.sourceId, |
| 498 | 504 | includeSchemas: false, |
| 499 | 505 | includeTypePreviews: false, |
| @@ -3,11 +3,10 @@ import type { · 2 unmodified lines | ||
| 3 | 3 | UpdateSourcePayload, |
| 4 | 4 | } from "./contracts"; |
| 5 | 5 | import { |
| 6 | − type AccountId, | |
| 6 | + type ScopeId, | |
| 7 | 7 | SourceIdSchema, |
| 8 | 8 | type Source, |
| 9 | 9 | type SourceId, |
| 10 | − type WorkspaceId, | |
| 11 | 10 | } from "../schema"; |
| 12 | 11 | import * as Either from "effect/Either"; |
| 13 | 12 | import * as Effect from "effect/Effect"; |
| @@ -16,15 +15,25 @@ import { · 2 unmodified lines | ||
| 16 | 15 | createSourceFromPayload, |
| 17 | 16 | updateSourceFromPayload, |
| 18 | 17 | } from "../runtime/sources/source-definitions"; |
| 19 | −import { getSourceAdapterForSource } from "../runtime/sources/source-adapters"; | |
| 20 | −import { mapPersistenceError } from "../runtime/policy/operations-shared"; | |
| 21 | −import { operationErrors } from "../runtime/policy/operation-errors"; | |
| 18 | +import { | |
| 19 | + getSourceAdapterForSource, | |
| 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 | 27 | import { |
| 23 | 28 | ExecutorStateStore, |
| 24 | 29 | type ExecutorStateStoreShape, |
| 25 | 30 | } from "../runtime/executor-state-store"; |
| 26 | −import { RuntimeSourceCatalogSyncService } from "../runtime/catalog/source/sync"; | |
| 27 | −import { RuntimeSourceStoreService } from "../runtime/sources/source-store"; | |
| 31 | +import { | |
| 32 | + RuntimeSourceCatalogSyncService, | |
| 33 | +} from "../runtime/catalog/source/sync"; | |
| 34 | +import { | |
| 35 | + RuntimeSourceStoreService, | |
| 36 | +} from "../runtime/sources/source-store"; | |
| 28 | 37 | |
| 29 | 38 | const sourceOps = { |
| 30 | 39 | list: operationErrors("sources.list"), |
| @@ -41,7 +50,7 @@ const syncArtifactsForSource = (input: { · 10 unmodified lines | ||
| 41 | 50 | store: ExecutorStateStoreShape; |
| 42 | 51 | sourceStore: Effect.Effect.Success<typeof RuntimeSourceStoreService>; |
| 43 | 52 | source: Source; |
| 44 | − actorAccountId: AccountId; | |
| 53 | + actorScopeId: ScopeId; | |
| 45 | 54 | operation: typeof sourceOps.create | typeof sourceOps.update; |
| 46 | 55 | }) => |
| 47 | 56 | Effect.gen(function* () { |
| @@ -59,7 +68,7 @@ const syncArtifactsForSource = (input: { · 11 unmodified lines | ||
| 59 | 68 | const synced = yield* Effect.either( |
| 60 | 69 | catalogSyncService.sync({ |
| 61 | 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 | 91 | yield* mapPersistenceError( |
| 83 | 92 | input.operation.child("source_connected"), |
| 84 | 93 | input.sourceStore.persistSource(connectedSource, { |
| 85 | − actorAccountId: input.actorAccountId, | |
| 94 | + actorScopeId: input.actorScopeId, | |
| 86 | 95 | }), |
| 87 | 96 | ); |
| 88 | 97 | return connectedSource; |
| @@ -114,7 +123,7 @@ const syncArtifactsForSource = (input: { · 25 unmodified lines | ||
| 114 | 123 | yield* mapPersistenceError( |
| 115 | 124 | input.operation.child("source_error"), |
| 116 | 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 | 139 | export const listSources = (input: { |
| 131 | − workspaceId: WorkspaceId; | |
| 132 | − accountId: AccountId; | |
| 140 | + scopeId: ScopeId; | |
| 141 | + actorScopeId: ScopeId; | |
| 133 | 142 | }) => |
| 134 | 143 | Effect.flatMap(ExecutorStateStore, () => |
| 135 | 144 | Effect.gen(function* () { |
| 136 | 145 | const sourceStore = yield* RuntimeSourceStoreService; |
| 137 | 146 | |
| 138 | 147 | return yield* sourceStore |
| 139 | − .loadSourcesInWorkspace(input.workspaceId, { | |
| 140 | − actorAccountId: input.accountId, | |
| 148 | + .loadSourcesInScope(input.scopeId, { | |
| 149 | + actorScopeId: input.actorScopeId, | |
| 141 | 150 | }) |
| 142 | 151 | .pipe( |
| 143 | 152 | Effect.mapError((error) => |
| @@ -151,8 +160,8 @@ export const listSources = (input: { · 7 unmodified lines | ||
| 151 | 160 | ); |
| 152 | 161 | |
| 153 | 162 | export const createSource = (input: { |
| 154 | − workspaceId: WorkspaceId; | |
| 155 | − accountId: AccountId; | |
| 163 | + scopeId: ScopeId; | |
| 164 | + actorScopeId: ScopeId; | |
| 156 | 165 | payload: CreateSourcePayload; |
| 157 | 166 | }) => |
| 158 | 167 | Effect.flatMap(ExecutorStateStore, (store) => |
| @@ -161,7 +170,7 @@ export const createSource = (input: { · 2 unmodified lines | ||
| 161 | 170 | const now = Date.now(); |
| 162 | 171 | |
| 163 | 172 | const source = yield* createSourceFromPayload({ |
| 164 | − workspaceId: input.workspaceId, | |
| 173 | + scopeId: input.scopeId, | |
| 165 | 174 | sourceId: SourceIdSchema.make(`src_${crypto.randomUUID()}`), |
| 166 | 175 | payload: input.payload, |
| 167 | 176 | now, |
| @@ -177,7 +186,7 @@ export const createSource = (input: { · 9 unmodified lines | ||
| 177 | 186 | const persistedSource = yield* mapPersistenceError( |
| 178 | 187 | sourceOps.create.child("persist"), |
| 179 | 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 | 194 | store, |
| 186 | 195 | sourceStore, |
| 187 | 196 | source: persistedSource, |
| 188 | − actorAccountId: input.accountId, | |
| 197 | + actorScopeId: input.actorScopeId, | |
| 189 | 198 | operation: sourceOps.create, |
| 190 | 199 | }); |
| 191 | 200 | |
| @@ -194,9 +203,9 @@ export const createSource = (input: { · 2 unmodified lines | ||
| 194 | 203 | ); |
| 195 | 204 | |
| 196 | 205 | export const getSource = (input: { |
| 197 | − workspaceId: WorkspaceId; | |
| 206 | + scopeId: ScopeId; | |
| 198 | 207 | sourceId: SourceId; |
| 199 | − accountId: AccountId; | |
| 208 | + actorScopeId: ScopeId; | |
| 200 | 209 | }) => |
| 201 | 210 | Effect.flatMap(ExecutorStateStore, () => |
| 202 | 211 | Effect.gen(function* () { |
| @@ -204,9 +213,9 @@ export const getSource = (input: { · 1 unmodified line | ||
| 204 | 213 | |
| 205 | 214 | return yield* sourceStore |
| 206 | 215 | .loadSourceById({ |
| 207 | − workspaceId: input.workspaceId, | |
| 216 | + scopeId: input.scopeId, | |
| 208 | 217 | sourceId: input.sourceId, |
| 209 | − actorAccountId: input.accountId, | |
| 218 | + actorScopeId: input.actorScopeId, | |
| 210 | 219 | }) |
| 211 | 220 | .pipe( |
| 212 | 221 | Effect.mapError((cause) => |
| @@ -214,7 +223,7 @@ export const getSource = (input: { · 1 unmodified line | ||
| 214 | 223 | cause.message.startsWith("Source not found:") |
| 215 | 224 | ? sourceOps.get.notFound( |
| 216 | 225 | "Source not found", |
| 217 | − `workspaceId=${input.workspaceId} sourceId=${input.sourceId}`, | |
| 226 | + `scopeId=${input.scopeId} sourceId=${input.sourceId}`, | |
| 218 | 227 | ) |
| 219 | 228 | : sourceOps.get.unknownStorage( |
| 220 | 229 | cause, |
| @@ -226,9 +235,9 @@ export const getSource = (input: { · 5 unmodified lines | ||
| 226 | 235 | ); |
| 227 | 236 | |
| 228 | 237 | export const updateSource = (input: { |
| 229 | − workspaceId: WorkspaceId; | |
| 238 | + scopeId: ScopeId; | |
| 230 | 239 | sourceId: SourceId; |
| 231 | − accountId: AccountId; | |
| 240 | + actorScopeId: ScopeId; | |
| 232 | 241 | payload: UpdateSourcePayload; |
| 233 | 242 | }) => |
| 234 | 243 | Effect.flatMap(ExecutorStateStore, (store) => |
| @@ -236,9 +245,9 @@ export const updateSource = (input: { · 1 unmodified line | ||
| 236 | 245 | const sourceStore = yield* RuntimeSourceStoreService; |
| 237 | 246 | const existingSource = yield* sourceStore |
| 238 | 247 | .loadSourceById({ |
| 239 | − workspaceId: input.workspaceId, | |
| 248 | + scopeId: input.scopeId, | |
| 240 | 249 | sourceId: input.sourceId, |
| 241 | − actorAccountId: input.accountId, | |
| 250 | + actorScopeId: input.actorScopeId, | |
| 242 | 251 | }) |
| 243 | 252 | .pipe( |
| 244 | 253 | Effect.mapError((cause) => |
| @@ -246,7 +255,7 @@ export const updateSource = (input: { · 1 unmodified line | ||
| 246 | 255 | cause.message.startsWith("Source not found:") |
| 247 | 256 | ? sourceOps.update.notFound( |
| 248 | 257 | "Source not found", |
| 249 | − `workspaceId=${input.workspaceId} sourceId=${input.sourceId}`, | |
| 258 | + `scopeId=${input.scopeId} sourceId=${input.sourceId}`, | |
| 250 | 259 | ) |
| 251 | 260 | : sourceOps.update.unknownStorage( |
| 252 | 261 | cause, |
| @@ -271,7 +280,7 @@ export const updateSource = (input: { · 18 unmodified lines | ||
| 271 | 280 | const persistedSource = yield* mapPersistenceError( |
| 272 | 281 | sourceOps.update.child("persist"), |
| 273 | 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 | 288 | store, |
| 280 | 289 | sourceStore, |
| 281 | 290 | source: persistedSource, |
| 282 | − actorAccountId: input.accountId, | |
| 291 | + actorScopeId: input.actorScopeId, | |
| 283 | 292 | operation: sourceOps.update, |
| 284 | 293 | }); |
| 285 | 294 | |
| @@ -288,7 +297,7 @@ export const updateSource = (input: { · 2 unmodified lines | ||
| 288 | 297 | ); |
| 289 | 298 | |
| 290 | 299 | export const removeSource = (input: { |
| 291 | − workspaceId: WorkspaceId; | |
| 300 | + scopeId: ScopeId; | |
| 292 | 301 | sourceId: SourceId; |
| 293 | 302 | }) => |
| 294 | 303 | Effect.flatMap(ExecutorStateStore, () => |
| @@ -297,7 +306,7 @@ export const removeSource = (input: { · 2 unmodified lines | ||
| 297 | 306 | const removed = yield* mapPersistenceError( |
| 298 | 307 | sourceOps.remove.child("remove"), |
| 299 | 308 | sourceStore.removeSourceById({ |
| 300 | − workspaceId: input.workspaceId, | |
| 309 | + scopeId: input.scopeId, | |
| 301 | 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 | 135 | export const SourceSchema = Schema.Struct({ |
| 136 | 136 | id: Schema.String, |
| 137 | − workspaceId: Schema.String, | |
| 137 | + scopeId: Schema.String, | |
| 138 | 138 | name: Schema.String, |
| 139 | 139 | kind: SourceKindSchema, |
| 140 | 140 | endpoint: Schema.String, |
| @@ -157,19 +157,19 @@ export const StoredSourceRecordSchema = Schema.Struct({ · 16 unmodified lines | ||
| 157 | 157 | bindingConfigJson: Schema.NullOr(Schema.String), |
| 158 | 158 | }); |
| 159 | 159 | |
| 160 | −export const WorkspaceSourceOauthClientRedirectModeSchema = Schema.Literal( | |
| 160 | +export const ScopedSourceOauthClientRedirectModeSchema = Schema.Literal( | |
| 161 | 161 | "app_callback", |
| 162 | 162 | "loopback", |
| 163 | 163 | ); |
| 164 | 164 | |
| 165 | −export const WorkspaceOauthClientIdSchema = Schema.String; | |
| 165 | +export const ScopeOauthClientIdSchema = Schema.String; | |
| 166 | 166 | |
| 167 | 167 | export const SourceOauthClientInputSchema = Schema.Struct({ |
| 168 | 168 | clientId: Schema.Trim.pipe(Schema.nonEmptyString()), |
| 169 | 169 | clientSecret: Schema.optional( |
| 170 | 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 | 175 | export type SecretRef = typeof SecretRefSchema.Type; |
| @@ -185,6 +185,6 @@ export type SourceAuth = typeof SourceAuthSchema.Type; · 9 unmodified lines | ||
| 185 | 185 | export type SourceBinding = typeof SourceBindingSchema.Type; |
| 186 | 186 | export type Source = typeof SourceSchema.Type; |
| 187 | 187 | export type StoredSourceRecord = typeof StoredSourceRecordSchema.Type; |
| 188 | −export type WorkspaceSourceOauthClientRedirectMode = | |
| 189 | − typeof WorkspaceSourceOauthClientRedirectModeSchema.Type; | |
| 188 | +export type ScopedSourceOauthClientRedirectMode = | |
| 189 | + typeof ScopedSourceOauthClientRedirectModeSchema.Type; | |
| 190 | 190 | export type SourceOauthClientInput = typeof SourceOauthClientInputSchema.Type; |
| @@ -81,7 +81,7 @@ const withJsonServer = async <T>(handler: (input: { · 80 unmodified lines | ||
| 81 | 81 | |
| 82 | 82 | const makeGoogleDiscoverySource = (discoveryUrl: string): Source => ({ |
| 83 | 83 | id: "src_google_gmail", |
| 84 | − workspaceId: "ws_test", | |
| 84 | + scopeId: "ws_test", | |
| 85 | 85 | name: "Gmail", |
| 86 | 86 | kind: "google_discovery", |
| 87 | 87 | endpoint: discoveryUrl, |
| @@ -38,7 +38,7 @@ import { · 37 unmodified lines | ||
| 38 | 38 | OptionalNullableStringSchema, |
| 39 | 39 | SourceCredentialRequiredError, |
| 40 | 40 | StringMapSchema, |
| 41 | − WorkspaceOauthClientIdSchema, | |
| 41 | + ScopeOauthClientIdSchema, | |
| 42 | 42 | createCatalogImportMetadata, |
| 43 | 43 | EXECUTABLE_BINDING_VERSION, |
| 44 | 44 | sourceCoreEffectError, |
| @@ -60,8 +60,8 @@ const GoogleDiscoveryConnectPayloadSchema = Schema.extend( · 15 unmodified lines | ||
| 60 | 60 | scopes: Schema.optional( |
| 61 | 61 | Schema.Array(Schema.Trim.pipe(Schema.nonEmptyString())), |
| 62 | 62 | ), |
| 63 | − workspaceOauthClientId: Schema.optional( | |
| 64 | − Schema.NullOr(WorkspaceOauthClientIdSchema), | |
| 63 | + scopeOauthClientId: Schema.optional( | |
| 64 | + Schema.NullOr(ScopeOauthClientIdSchema), | |
| 65 | 65 | ), |
| 66 | 66 | oauthClient: ConnectOauthClientSchema, |
| 67 | 67 | name: OptionalNullableStringSchema, |
| @@ -14,6 +14,8 @@ Current rules: · 13 unmodified lines | ||
| 14 | 14 | - `executor-monorepo/no-cross-workspace-relative-imports` |
| 15 | 15 | - `executor-monorepo/no-direct-effect-tag-read` |
| 16 | 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 | 19 | - `executor-monorepo/no-node-fs-with-effect-imports` |
| 18 | 20 | - `executor-monorepo/no-raw-effect-fail-errors` |
| 19 | 21 | - `executor-monorepo/no-yield-effect-fail` |
| @@ -4,6 +4,8 @@ import noCrossWorkspaceRelativeImports from "./rules/no-cross-workspace-relative · 3 unmodified lines | ||
| 4 | 4 | import noAsyncEffectVitestTests from "./rules/no-async-effect-vitest-tests.mjs"; |
| 5 | 5 | import noDirectEffectTagRead from "./rules/no-direct-effect-tag-read.mjs"; |
| 6 | 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 | 9 | import noNodeFsWithEffectImports from "./rules/no-node-fs-with-effect-imports.mjs"; |
| 8 | 10 | import noRawEffectFailErrors from "./rules/no-raw-effect-fail-errors.mjs"; |
| 9 | 11 | import noYieldEffectFail from "./rules/no-yield-effect-fail.mjs"; |
| @@ -18,6 +20,8 @@ export default definePlugin({ · 8 unmodified lines | ||
| 18 | 20 | "no-cross-workspace-relative-imports": noCrossWorkspaceRelativeImports, |
| 19 | 21 | "no-direct-effect-tag-read": noDirectEffectTagRead, |
| 20 | 22 | "no-effect-run-in-effect-vitest-tests": noEffectRunInEffectVitestTests, |
| 23 | + "no-manual-httpapi-openapi-bridge": noManualHttpApiOpenApiBridge, | |
| 24 | + "no-manual-openapi-documents": noManualOpenApiDocuments, | |
| 21 | 25 | "no-node-fs-with-effect-imports": noNodeFsWithEffectImports, |
| 22 | 26 | "no-raw-effect-fail-errors": noRawEffectFailErrors, |
| 23 | 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 | +}); | |