Unified · Split
| @@ -1,93 +0,0 @@ | ||
| 1 | −import { | |
| 2 | − type SourceCredentialBinding, | |
| 3 | − SourceCredentialBindingSchema, | |
| 4 | −} from "#schema"; | |
| 5 | −import * as Option from "effect/Option"; | |
| 6 | −import { Schema } from "effect"; | |
| 7 | −import { and, asc, eq } from "drizzle-orm"; | |
| 8 | − | |
| 9 | −import type { DrizzleClient } from "../client"; | |
| 10 | −import type { DrizzleTables } from "../schema"; | |
| 11 | −import { firstOption, withoutCreatedAt } from "./shared"; | |
| 12 | − | |
| 13 | −const decodeSourceCredentialBinding = Schema.decodeUnknownSync( | |
| 14 | − SourceCredentialBindingSchema, | |
| 15 | −); | |
| 16 | − | |
| 17 | −export const createSourceCredentialBindingsRepo = ( | |
| 18 | − client: DrizzleClient, | |
| 19 | − tables: DrizzleTables, | |
| 20 | −) => ({ | |
| 21 | − listByWorkspaceId: (workspaceId: SourceCredentialBinding["workspaceId"]) => | |
| 22 | − client.use("rows.source_credential_bindings.list_by_workspace", async (db) => { | |
| 23 | − const rows = await db | |
| 24 | − .select() | |
| 25 | − .from(tables.sourceCredentialBindingsTable) | |
| 26 | − .where(eq(tables.sourceCredentialBindingsTable.workspaceId, workspaceId)) | |
| 27 | − .orderBy( | |
| 28 | − asc(tables.sourceCredentialBindingsTable.updatedAt), | |
| 29 | − asc(tables.sourceCredentialBindingsTable.sourceId), | |
| 30 | − ); | |
| 31 | − | |
| 32 | − return rows.map((row) => decodeSourceCredentialBinding(row)); | |
| 33 | − }), | |
| 34 | − | |
| 35 | − getByWorkspaceAndSourceId: ( | |
| 36 | − workspaceId: SourceCredentialBinding["workspaceId"], | |
| 37 | − sourceId: SourceCredentialBinding["sourceId"], | |
| 38 | − ) => | |
| 39 | − client.use( | |
| 40 | − "rows.source_credential_bindings.get_by_workspace_and_source_id", | |
| 41 | − async (db) => { | |
| 42 | − const rows = await db | |
| 43 | − .select() | |
| 44 | − .from(tables.sourceCredentialBindingsTable) | |
| 45 | − .where( | |
| 46 | − and( | |
| 47 | − eq(tables.sourceCredentialBindingsTable.workspaceId, workspaceId), | |
| 48 | − eq(tables.sourceCredentialBindingsTable.sourceId, sourceId), | |
| 49 | − ), | |
| 50 | − ) | |
| 51 | − .limit(1); | |
| 52 | − | |
| 53 | − const row = firstOption(rows); | |
| 54 | − return Option.isSome(row) | |
| 55 | − ? Option.some(decodeSourceCredentialBinding(row.value)) | |
| 56 | − : Option.none<SourceCredentialBinding>(); | |
| 57 | − }, | |
| 58 | − ), | |
| 59 | − | |
| 60 | − upsert: (binding: SourceCredentialBinding) => | |
| 61 | − client.use("rows.source_credential_bindings.upsert", async (db) => { | |
| 62 | − await db | |
| 63 | − .insert(tables.sourceCredentialBindingsTable) | |
| 64 | − .values(binding) | |
| 65 | − .onConflictDoUpdate({ | |
| 66 | − target: [ | |
| 67 | − tables.sourceCredentialBindingsTable.workspaceId, | |
| 68 | − tables.sourceCredentialBindingsTable.sourceId, | |
| 69 | − ], | |
| 70 | − set: { | |
| 71 | − ...withoutCreatedAt(binding), | |
| 72 | − }, | |
| 73 | − }); | |
| 74 | − }), | |
| 75 | − | |
| 76 | − removeByWorkspaceAndSourceId: ( | |
| 77 | − workspaceId: SourceCredentialBinding["workspaceId"], | |
| 78 | − sourceId: SourceCredentialBinding["sourceId"], | |
| 79 | − ) => | |
| 80 | − client.use("rows.source_credential_bindings.remove", async (db) => { | |
| 81 | − const deleted = await db | |
| 82 | − .delete(tables.sourceCredentialBindingsTable) | |
| 83 | − .where( | |
| 84 | − and( | |
| 85 | − eq(tables.sourceCredentialBindingsTable.workspaceId, workspaceId), | |
| 86 | − eq(tables.sourceCredentialBindingsTable.sourceId, sourceId), | |
| 87 | − ), | |
| 88 | − ) | |
| 89 | − .returning(); | |
| 90 | − | |
| 91 | − return deleted.length > 0; | |
| 92 | − }), | |
| 93 | −}); | |
| @@ -12,6 +12,8 @@ import { · 11 unmodified lines | ||
| 12 | 12 | ExecutionInteractionIdSchema, |
| 13 | 13 | SecretMaterialIdSchema, |
| 14 | 14 | SourceIdSchema, |
| 15 | + SourceRecipeIdSchema, | |
| 16 | + SourceRecipeRevisionIdSchema, | |
| 15 | 17 | } from "#schema"; |
| 16 | 18 | import type { ToolPath } from "@executor/codemode-core"; |
| 17 | 19 | |
| @@ -278,12 +280,15 @@ describe("control-plane-runtime", () => { · 260 unmodified lines | ||
| 278 | 280 | yield* runtime.persistence.rows.sources.insert({ |
| 279 | 281 | id: sourceId, |
| 280 | 282 | workspaceId: installation.workspaceId, |
| 283 | + recipeId: SourceRecipeIdSchema.make(`src_recipe_${sourceId}`), | |
| 284 | + recipeRevisionId: SourceRecipeRevisionIdSchema.make(`src_recipe_rev_${sourceId}`), | |
| 281 | 285 | name: "GitHub", |
| 282 | 286 | kind: "openapi", |
| 283 | 287 | endpoint: "https://api.github.com", |
| 284 | 288 | status: "auth_required", |
| 285 | 289 | enabled: true, |
| 286 | 290 | namespace: "github", |
| 291 | + bindingConfigJson: null, | |
| 287 | 292 | transport: null, |
| 288 | 293 | queryParamsJson: null, |
| 289 | 294 | headersJson: null, |
| @@ -435,12 +440,15 @@ describe("control-plane-runtime", () => { · 145 unmodified lines | ||
| 435 | 440 | yield* runtime.persistence.rows.sources.insert({ |
| 436 | 441 | id: sourceId, |
| 437 | 442 | workspaceId: installation.workspaceId, |
| 443 | + recipeId: SourceRecipeIdSchema.make(`src_recipe_${sourceId}`), | |
| 444 | + recipeRevisionId: SourceRecipeRevisionIdSchema.make(`src_recipe_rev_${sourceId}`), | |
| 438 | 445 | name: "GitHub", |
| 439 | 446 | kind: "openapi", |
| 440 | 447 | endpoint: "https://api.github.com", |
| 441 | 448 | status: "auth_required", |
| 442 | 449 | enabled: true, |
| 443 | 450 | namespace: "github", |
| 451 | + bindingConfigJson: null, | |
| 444 | 452 | transport: null, |
| 445 | 453 | queryParamsJson: null, |
| 446 | 454 | headersJson: null, |
| @@ -32,6 +32,8 @@ import { · 31 unmodified lines | ||
| 32 | 32 | ExecutionIdSchema, |
| 33 | 33 | SecretMaterialIdSchema, |
| 34 | 34 | SourceIdSchema, |
| 35 | + SourceRecipeIdSchema, | |
| 36 | + SourceRecipeRevisionIdSchema, | |
| 35 | 37 | WorkspaceIdSchema, |
| 36 | 38 | } from "#schema"; |
| 37 | 39 | import * as Context from "effect/Context"; |
| @@ -271,7 +273,8 @@ const testGraphqlSchema = new GraphQLSchema({ · 233 unmodified lines | ||
| 271 | 273 | const closeScope = (scope: Scope.CloseableScope) => |
| 272 | 274 | Scope.close(scope, Exit.void).pipe(Effect.orDie); |
| 273 | 275 | |
| 274 | −const makePersistence = Effect.acquireRelease( | |
| 276 | +const makePersistence: Effect.Effect<SqlControlPlanePersistence, unknown, Scope.Scope> = | |
| 277 | + Effect.acquireRelease( | |
| 275 | 278 | createSqlControlPlanePersistence({ |
| 276 | 279 | localDataDir: ":memory:", |
| 277 | 280 | }), |
| @@ -280,7 +283,7 @@ const makePersistence = Effect.acquireRelease( · 2 unmodified lines | ||
| 280 | 283 | try: () => persistence.close(), |
| 281 | 284 | catch: (cause) => (cause instanceof Error ? cause : new Error(String(cause))), |
| 282 | 285 | }).pipe(Effect.orDie), |
| 283 | −); | |
| 286 | + ); | |
| 284 | 287 | |
| 285 | 288 | const makeCountedMcpServer = Effect.acquireRelease( |
| 286 | 289 | Effect.promise<CountedMcpServer>( |
| @@ -644,12 +647,15 @@ const persistConnectedEchoTool = (input: { · 357 unmodified lines | ||
| 644 | 647 | yield* input.persistence.rows.sources.insert({ |
| 645 | 648 | id: input.sourceId, |
| 646 | 649 | workspaceId: input.workspaceId, |
| 650 | + recipeId: SourceRecipeIdSchema.make(`src_recipe_${input.sourceId}`), | |
| 651 | + recipeRevisionId: SourceRecipeRevisionIdSchema.make(`src_recipe_rev_${input.sourceId}`), | |
| 647 | 652 | name: "Counted MCP", |
| 648 | 653 | kind: "mcp", |
| 649 | 654 | endpoint: input.endpoint, |
| 650 | 655 | status: "connected", |
| 651 | 656 | enabled: true, |
| 652 | 657 | namespace: "counted", |
| 658 | + bindingConfigJson: null, | |
| 653 | 659 | transport: "auto", |
| 654 | 660 | queryParamsJson: null, |
| 655 | 661 | headersJson: null, |
| @@ -816,12 +822,15 @@ const persistConnectedGithubOpenApiSource = (input: { · 160 unmodified lines | ||
| 816 | 822 | yield* input.persistence.rows.sources.insert({ |
| 817 | 823 | id: input.sourceId, |
| 818 | 824 | workspaceId: input.workspaceId, |
| 825 | + recipeId: SourceRecipeIdSchema.make(`src_recipe_${input.sourceId}`), | |
| 826 | + recipeRevisionId: SourceRecipeRevisionIdSchema.make(`src_recipe_rev_${input.sourceId}`), | |
| 819 | 827 | name: "GitHub", |
| 820 | 828 | kind: "openapi", |
| 821 | 829 | endpoint: input.endpoint ?? "https://api.github.com", |
| 822 | 830 | status: "connected", |
| 823 | 831 | enabled: true, |
| 824 | 832 | namespace: "github", |
| 833 | + bindingConfigJson: null, | |
| 825 | 834 | transport: null, |
| 826 | 835 | queryParamsJson: null, |
| 827 | 836 | headersJson: null, |
| @@ -839,6 +848,8 @@ const persistConnectedGithubOpenApiSource = (input: { · 11 unmodified lines | ||
| 839 | 848 | yield* input.persistence.rows.credentials.upsert({ |
| 840 | 849 | id: credentialId, |
| 841 | 850 | workspaceId: input.workspaceId, |
| 851 | + sourceId: input.sourceId, | |
| 852 | + actorAccountId: null, | |
| 842 | 853 | authKind: "bearer", |
| 843 | 854 | authHeaderName: "Authorization", |
| 844 | 855 | authPrefix: "Bearer ", |
| @@ -849,14 +860,6 @@ const persistConnectedGithubOpenApiSource = (input: { · 4 unmodified lines | ||
| 849 | 860 | createdAt: now, |
| 850 | 861 | updatedAt: now, |
| 851 | 862 | }); |
| 852 | − yield* input.persistence.rows.sourceCredentialBindings.upsert({ | |
| 853 | − id: `src_cred_bind_${randomUUID()}`, | |
| 854 | − workspaceId: input.workspaceId, | |
| 855 | − sourceId: input.sourceId, | |
| 856 | − credentialId, | |
| 857 | − createdAt: now, | |
| 858 | − updatedAt: now, | |
| 859 | − }); | |
| 860 | 863 | }; |
| 861 | 864 | |
| 862 | 865 | }); |