Unified · Split
| @@ -140,7 +140,6 @@ const seedWorkspaceSourceState = (input: { · 139 unmodified lines | |||
| 140 | yield* input.persistence.rows.sources.insert({ | 140 | yield* input.persistence.rows.sources.insert({ |
| 141 | id: input.sourceId, | 141 | id: input.sourceId, |
| 142 | workspaceId: input.workspaceId, | 142 | workspaceId: input.workspaceId, |
| 143 | configKey: null, | ||
| 144 | recipeId, | 143 | recipeId, |
| 145 | recipeRevisionId, | 144 | recipeRevisionId, |
| 146 | name: "Github", | 145 | name: "Github", |
| @@ -278,7 +277,6 @@ describe("control-plane-persistence-drizzle", () => { · 131 unmodified lines | |||
| 278 | yield* persistence.rows.sources.insert({ | 277 | yield* persistence.rows.sources.insert({ |
| 279 | id: SourceIdSchema.make("src_1"), | 278 | id: SourceIdSchema.make("src_1"), |
| 280 | workspaceId, | 279 | workspaceId, |
| 281 | configKey: null, | ||
| 282 | recipeId: SourceRecipeIdSchema.make("src_recipe_1"), | 280 | recipeId: SourceRecipeIdSchema.make("src_recipe_1"), |
| 283 | recipeRevisionId: SourceRecipeRevisionIdSchema.make("src_recipe_rev_1"), | 281 | recipeRevisionId: SourceRecipeRevisionIdSchema.make("src_recipe_rev_1"), |
| 284 | name: "Github", | 282 | name: "Github", |
| @@ -863,7 +861,6 @@ describe("control-plane-persistence-drizzle", () => { · 578 unmodified lines | |||
| 863 | yield* persistence.rows.sources.insert({ | 861 | yield* persistence.rows.sources.insert({ |
| 864 | id: SourceIdSchema.make("src_shared_removed"), | 862 | id: SourceIdSchema.make("src_shared_removed"), |
| 865 | workspaceId: removedWorkspaceId, | 863 | workspaceId: removedWorkspaceId, |
| 866 | configKey: null, | ||
| 867 | recipeId: sharedRecipeId, | 864 | recipeId: sharedRecipeId, |
| 868 | recipeRevisionId: sharedRecipeRevisionId, | 865 | recipeRevisionId: sharedRecipeRevisionId, |
| 869 | name: "Github Removed", | 866 | name: "Github Removed", |
| @@ -882,7 +879,6 @@ describe("control-plane-persistence-drizzle", () => { · 12 unmodified lines | |||
| 882 | yield* persistence.rows.sources.insert({ | 879 | yield* persistence.rows.sources.insert({ |
| 883 | id: SourceIdSchema.make("src_shared_remaining"), | 880 | id: SourceIdSchema.make("src_shared_remaining"), |
| 884 | workspaceId: remainingWorkspaceId, | 881 | workspaceId: remainingWorkspaceId, |
| 885 | configKey: null, | ||
| 886 | recipeId: sharedRecipeId, | 882 | recipeId: sharedRecipeId, |
| 887 | recipeRevisionId: sharedRecipeRevisionId, | 883 | recipeRevisionId: sharedRecipeRevisionId, |
| 888 | name: "Github Remaining", | 884 | name: "Github Remaining", |
| @@ -188,7 +188,6 @@ const seedMigratedSourceRecipe = (input: { · 187 unmodified lines | |||
| 188 | yield* input.persistence.rows.sources.insert({ | 188 | yield* input.persistence.rows.sources.insert({ |
| 189 | id: input.sourceId, | 189 | id: input.sourceId, |
| 190 | workspaceId: input.workspaceId, | 190 | workspaceId: input.workspaceId, |
| 191 | configKey: null, | ||
| 192 | recipeId, | 191 | recipeId, |
| 193 | recipeRevisionId, | 192 | recipeRevisionId, |
| 194 | name: input.kind === "openapi" ? "GitHub" : "GraphQL Demo", | 193 | name: input.kind === "openapi" ? "GitHub" : "GraphQL Demo", |
| @@ -325,7 +325,7 @@ describe("control-plane-runtime", () => { · 324 unmodified lines | |||
| 325 | const runtime = yield* makeRuntime; | 325 | const runtime = yield* makeRuntime; |
| 326 | const installation = runtime.localInstallation; | 326 | const installation = runtime.localInstallation; |
| 327 | const executionId = ExecutionIdSchema.make("exec_local_credential"); | 327 | const executionId = ExecutionIdSchema.make("exec_local_credential"); |
| 328 | const sourceId = SourceIdSchema.make("src_local_credential"); | 328 | const sourceId = SourceIdSchema.make("github"); |
| 329 | const interactionSuffix = "executor.sources.add:test"; | 329 | const interactionSuffix = "executor.sources.add:test"; |
| 330 | const interactionId = ExecutionInteractionIdSchema.make( | 330 | const interactionId = ExecutionInteractionIdSchema.make( |
| 331 | `${executionId}:${interactionSuffix}`, | 331 | `${executionId}:${interactionSuffix}`, |
| @@ -488,7 +488,7 @@ describe("control-plane-runtime", () => { · 156 unmodified lines | |||
| 488 | const runtime = yield* makeRuntime; | 488 | const runtime = yield* makeRuntime; |
| 489 | const installation = runtime.localInstallation; | 489 | const installation = runtime.localInstallation; |
| 490 | const executionId = ExecutionIdSchema.make("exec_local_credential_continue"); | 490 | const executionId = ExecutionIdSchema.make("exec_local_credential_continue"); |
| 491 | const sourceId = SourceIdSchema.make("src_local_credential_continue"); | 491 | const sourceId = SourceIdSchema.make("github"); |
| 492 | const interactionSuffix = "executor.sources.add:continue"; | 492 | const interactionSuffix = "executor.sources.add:continue"; |
| 493 | const interactionId = ExecutionInteractionIdSchema.make( | 493 | const interactionId = ExecutionInteractionIdSchema.make( |
| 494 | `${executionId}:${interactionSuffix}`, | 494 | `${executionId}:${interactionSuffix}`, |
| @@ -29,7 +29,6 @@ const LOCAL_SOURCE_ARTIFACT_VERSION = 1 as const; · 28 unmodified lines | |||
| 29 | export const LocalSourceArtifactSchema = Schema.Struct({ | 29 | export const LocalSourceArtifactSchema = Schema.Struct({ |
| 30 | version: Schema.Literal(LOCAL_SOURCE_ARTIFACT_VERSION), | 30 | version: Schema.Literal(LOCAL_SOURCE_ARTIFACT_VERSION), |
| 31 | sourceId: SourceIdSchema, | 31 | sourceId: SourceIdSchema, |
| 32 | configKey: Schema.String, | ||
| 33 | recipeId: SourceRecipeIdSchema, | 32 | recipeId: SourceRecipeIdSchema, |
| 34 | generatedAt: TimestampMsSchema, | 33 | generatedAt: TimestampMsSchema, |
| 35 | revision: StoredSourceRecipeRevisionRecordSchema, | 34 | revision: StoredSourceRecipeRevisionRecordSchema, |
| @@ -44,12 +43,12 @@ const decodeLocalSourceArtifact = Schema.decodeUnknownSync(LocalSourceArtifactSc · 8 unmodified lines | |||
| 44 | 43 | ||
| 45 | const localSourceArtifactPath = (input: { | 44 | const localSourceArtifactPath = (input: { |
| 46 | context: ResolvedLocalWorkspaceContext; | 45 | context: ResolvedLocalWorkspaceContext; |
| 47 | configKey: string; | 46 | sourceId: string; |
| 48 | }): string => | 47 | }): string => |
| 49 | join( | 48 | join( |
| 50 | input.context.artifactsDirectory, | 49 | input.context.artifactsDirectory, |
| 51 | "sources", | 50 | "sources", |
| 52 | `${input.configKey}.json`, | 51 | `${input.sourceId}.json`, |
| 53 | ); | 52 | ); |
| 54 | 53 | ||
| 55 | const canonicalMaterializationHash = (input: { | 54 | const canonicalMaterializationHash = (input: { |
| @@ -112,7 +111,6 @@ const bindRevisionId = <T extends { recipeRevisionId: string }>( · 56 unmodified lines | |||
| 112 | 111 | ||
| 113 | export const buildLocalSourceArtifact = (input: { | 112 | export const buildLocalSourceArtifact = (input: { |
| 114 | source: Source; | 113 | source: Source; |
| 115 | configKey: string; | ||
| 116 | materialization: SourceRecipeMaterialization; | 114 | materialization: SourceRecipeMaterialization; |
| 117 | }): LocalSourceArtifact => { | 115 | }): LocalSourceArtifact => { |
| 118 | const recipeId: SourceRecipeId = stableSourceRecipeId(input.source); | 116 | const recipeId: SourceRecipeId = stableSourceRecipeId(input.source); |
| @@ -131,7 +129,6 @@ export const buildLocalSourceArtifact = (input: { · 12 unmodified lines | |||
| 131 | return { | 129 | return { |
| 132 | version: LOCAL_SOURCE_ARTIFACT_VERSION, | 130 | version: LOCAL_SOURCE_ARTIFACT_VERSION, |
| 133 | sourceId: input.source.id, | 131 | sourceId: input.source.id, |
| 134 | configKey: input.configKey, | ||
| 135 | recipeId, | 132 | recipeId, |
| 136 | generatedAt: now, | 133 | generatedAt: now, |
| 137 | revision, | 134 | revision, |
| @@ -143,7 +140,7 @@ export const buildLocalSourceArtifact = (input: { · 5 unmodified lines | |||
| 143 | 140 | ||
| 144 | export const readLocalSourceArtifact = async (input: { | 141 | export const readLocalSourceArtifact = async (input: { |
| 145 | context: ResolvedLocalWorkspaceContext; | 142 | context: ResolvedLocalWorkspaceContext; |
| 146 | configKey: string; | 143 | sourceId: string; |
| 147 | }): Promise<LocalSourceArtifact | null> => { | 144 | }): Promise<LocalSourceArtifact | null> => { |
| 148 | const path = localSourceArtifactPath(input); | 145 | const path = localSourceArtifactPath(input); |
| 149 | 146 | ||
| @@ -166,7 +163,7 @@ export const readLocalSourceArtifact = async (input: { · 16 unmodified lines | |||
| 166 | 163 | ||
| 167 | export const writeLocalSourceArtifact = async (input: { | 164 | export const writeLocalSourceArtifact = async (input: { |
| 168 | context: ResolvedLocalWorkspaceContext; | 165 | context: ResolvedLocalWorkspaceContext; |
| 169 | configKey: string; | 166 | sourceId: string; |
| 170 | artifact: LocalSourceArtifact; | 167 | artifact: LocalSourceArtifact; |
| 171 | }): Promise<void> => { | 168 | }): Promise<void> => { |
| 172 | const path = localSourceArtifactPath(input); | 169 | const path = localSourceArtifactPath(input); |
| @@ -178,7 +175,7 @@ export const writeLocalSourceArtifact = async (input: { · 5 unmodified lines | |||
| 178 | 175 | ||
| 179 | export const removeLocalSourceArtifact = async (input: { | 176 | export const removeLocalSourceArtifact = async (input: { |
| 180 | context: ResolvedLocalWorkspaceContext; | 177 | context: ResolvedLocalWorkspaceContext; |
| 181 | configKey: string; | 178 | sourceId: string; |
| 182 | }): Promise<void> => { | 179 | }): Promise<void> => { |
| 183 | const path = localSourceArtifactPath(input); | 180 | const path = localSourceArtifactPath(input); |
| 184 | 181 | ||
| @@ -3,7 +3,6 @@ import { join } from "node:path"; · 2 unmodified lines | |||
| 3 | 3 | ||
| 4 | import { | 4 | import { |
| 5 | PolicyIdSchema, | 5 | PolicyIdSchema, |
| 6 | SourceIdSchema, | ||
| 7 | SourceStatusSchema, | 6 | SourceStatusSchema, |
| 8 | TimestampMsSchema, | 7 | TimestampMsSchema, |
| 9 | } from "#schema"; | 8 | } from "#schema"; |
| @@ -14,7 +13,6 @@ import type { ResolvedLocalWorkspaceContext } from "./local-config"; · 4 unmodified lines | |||
| 14 | const WORKSPACE_STATE_BASENAME = "workspace-state.json"; | 13 | const WORKSPACE_STATE_BASENAME = "workspace-state.json"; |
| 15 | 14 | ||
| 16 | const LocalWorkspaceSourceStateSchema = Schema.Struct({ | 15 | const LocalWorkspaceSourceStateSchema = Schema.Struct({ |
| 17 | id: SourceIdSchema, | ||
| 18 | status: SourceStatusSchema, | 16 | status: SourceStatusSchema, |
| 19 | lastError: Schema.NullOr(Schema.String), | 17 | lastError: Schema.NullOr(Schema.String), |
| 20 | sourceHash: Schema.NullOr(Schema.String), | 18 | sourceHash: Schema.NullOr(Schema.String), |
| @@ -42,12 +42,11 @@ const toApprovalMode = (approval: LocalConfigPolicy["approval"]): Policy["approv · 41 unmodified lines | |||
| 42 | approval === "manual" ? "required" : "auto"; | 42 | approval === "manual" ? "required" : "auto"; |
| 43 | 43 | ||
| 44 | export const deriveSourceConfigKey = ( | 44 | export const deriveSourceConfigKey = ( |
| 45 | source: Pick<Source, "configKey" | "namespace" | "name">, | 45 | source: Pick<Source, "namespace" | "name">, |
| 46 | used: Set<string>, | 46 | used: Set<string>, |
| 47 | ): string => { | 47 | ): string => { |
| 48 | const base = | 48 | const base = |
| 49 | trimOrNull(source.configKey) | 49 | trimOrNull(source.namespace) |
| 50 | ?? trimOrNull(source.namespace) | ||
| 51 | ?? trimOrNull(source.name) | 50 | ?? trimOrNull(source.name) |
| 52 | ?? "source"; | 51 | ?? "source"; |
| 53 | const slugBase = slugify(base) || "source"; | 52 | const slugBase = slugify(base) || "source"; |
| @@ -112,14 +111,15 @@ const configAuthFromStoredSource = (input: { · 58 unmodified lines | |||
| 112 | 111 | ||
| 113 | export const configSourceFromStoredSource = (input: { | 112 | export const configSourceFromStoredSource = (input: { |
| 114 | source: Source; | 113 | source: Source; |
| 114 | sourceId: string; | ||
| 115 | config: LocalExecutorConfig | null; | 115 | config: LocalExecutorConfig | null; |
| 116 | }): LocalConfigSource => { | 116 | }): LocalConfigSource => { |
| 117 | const auth = configAuthFromStoredSource(input); | 117 | const auth = configAuthFromStoredSource(input); |
| 118 | const common = { | 118 | const common = { |
| 119 | ...(trimOrNull(input.source.name) !== trimOrNull(input.source.configKey) | 119 | ...(trimOrNull(input.source.name) !== trimOrNull(input.sourceId) |
| 120 | ? { name: input.source.name } | 120 | ? { name: input.source.name } |
| 121 | : {}), | 121 | : {}), |
| 122 | ...(trimOrNull(input.source.namespace) !== trimOrNull(input.source.configKey) | 122 | ...(trimOrNull(input.source.namespace) !== trimOrNull(input.sourceId) |
| 123 | ? { namespace: input.source.namespace ?? undefined } | 123 | ? { namespace: input.source.namespace ?? undefined } |
| 124 | : {}), | 124 | : {}), |
| 125 | ...(input.source.enabled === false ? { enabled: false } : {}), | 125 | ...(input.source.enabled === false ? { enabled: false } : {}), |
| @@ -231,10 +231,8 @@ const exportWorkspaceConfig = (input: { · 105 unmodified lines | |||
| 231 | const configKey = deriveSourceConfigKey(source, sourceKeys); | 231 | const configKey = deriveSourceConfigKey(source, sourceKeys); |
| 232 | sourceMappings.push({ configKey, source }); | 232 | sourceMappings.push({ configKey, source }); |
| 233 | sourcesConfig[configKey] = configSourceFromStoredSource({ | 233 | sourcesConfig[configKey] = configSourceFromStoredSource({ |
| 234 | source: { | 234 | source, |
| 235 | ...source, | 235 | sourceId: configKey, |
| 236 | configKey, | ||
| 237 | }, | ||
| 238 | config: input.loadedConfig.config, | 236 | config: input.loadedConfig.config, |
| 239 | }); | 237 | }); |
| 240 | } | 238 | } |
| @@ -304,7 +302,6 @@ const exportWorkspaceConfig = (input: { · 63 unmodified lines | |||
| 304 | sources: { | 302 | sources: { |
| 305 | ...workspaceState.sources, | 303 | ...workspaceState.sources, |
| 306 | [configKey]: { | 304 | [configKey]: { |
| 307 | id: source.id, | ||
| 308 | status: source.status, | 305 | status: source.status, |
| 309 | lastError: source.lastError, | 306 | lastError: source.lastError, |
| 310 | sourceHash: source.sourceHash, | 307 | sourceHash: source.sourceHash, |
| @@ -324,13 +321,13 @@ const exportWorkspaceConfig = (input: { · 13 unmodified lines | |||
| 324 | try: () => | 321 | try: () => |
| 325 | writeLocalSourceArtifact({ | 322 | writeLocalSourceArtifact({ |
| 326 | context: input.context, | 323 | context: input.context, |
| 327 | configKey, | 324 | sourceId: configKey, |
| 328 | artifact: buildLocalSourceArtifact({ | 325 | artifact: buildLocalSourceArtifact({ |
| 329 | source: { | 326 | source: { |
| 330 | ...source, | 327 | ...source, |
| 328 | id: configKey as Source["id"], | ||
| 331 | sourceHash: revision.manifestHash ?? source.sourceHash, | 329 | sourceHash: revision.manifestHash ?? source.sourceHash, |
| 332 | }, | 330 | }, |
| 333 | configKey, | ||
| 334 | materialization: { | 331 | materialization: { |
| 335 | manifestJson: revision.manifestJson, | 332 | manifestJson: revision.manifestJson, |
| 336 | manifestHash: revision.manifestHash, | 333 | manifestHash: revision.manifestHash, |
| @@ -12,7 +12,6 @@ import { resolveSourceAuthMaterial } from "./source-auth-material"; · 11 unmodified lines | |||
| 12 | const makeSource = (overrides: Partial<Source> = {}): Source => ({ | 12 | const makeSource = (overrides: Partial<Source> = {}): Source => ({ |
| 13 | id: SourceIdSchema.make("src_tool_artifacts"), | 13 | id: SourceIdSchema.make("src_tool_artifacts"), |
| 14 | workspaceId: WorkspaceIdSchema.make("ws_tool_artifacts"), | 14 | workspaceId: WorkspaceIdSchema.make("ws_tool_artifacts"), |
| 15 | configKey: null, | ||
| 16 | name: "GitHub", | 15 | name: "GitHub", |
| 17 | kind: "openapi", | 16 | kind: "openapi", |
| 18 | endpoint: "https://api.github.com", | 17 | endpoint: "https://api.github.com", |
| @@ -32,7 +32,6 @@ import { resolveSourceAuthMaterial } from "./source-auth-material"; · 31 unmodified lines | |||
| 32 | const makeExistingOpenApiSource = (auth: Source["auth"]): Source => ({ | 32 | const makeExistingOpenApiSource = (auth: Source["auth"]): Source => ({ |
| 33 | id: "src_test" as Source["id"], | 33 | id: "src_test" as Source["id"], |
| 34 | workspaceId: "ws_test" as Source["workspaceId"], | 34 | workspaceId: "ws_test" as Source["workspaceId"], |
| 35 | configKey: null, | ||
| 36 | name: "GitHub", | 35 | name: "GitHub", |
| 37 | kind: "openapi", | 36 | kind: "openapi", |
| 38 | endpoint: "https://api.github.com", | 37 | endpoint: "https://api.github.com", |
| @@ -44,7 +44,6 @@ const mcpBinding = (input: { · 43 unmodified lines | |||
| 44 | const makeSource = (overrides: Partial<Source> = {}): Source => ({ | 44 | const makeSource = (overrides: Partial<Source> = {}): Source => ({ |
| 45 | id: SourceIdSchema.make("src_source_definitions"), | 45 | id: SourceIdSchema.make("src_source_definitions"), |
| 46 | workspaceId: WorkspaceIdSchema.make("ws_source_definitions"), | 46 | workspaceId: WorkspaceIdSchema.make("ws_source_definitions"), |
| 47 | configKey: null, | ||
| 48 | name: "GitHub", | 47 | name: "GitHub", |
| 49 | kind: "openapi", | 48 | kind: "openapi", |
| 50 | endpoint: "https://api.github.com", | 49 | endpoint: "https://api.github.com", |
| @@ -232,7 +232,6 @@ export const createSourceFromPayload = (input: { · 231 unmodified lines | |||
| 232 | return yield* validateSourceByKind({ | 232 | return yield* validateSourceByKind({ |
| 233 | id: input.sourceId, | 233 | id: input.sourceId, |
| 234 | workspaceId: input.workspaceId, | 234 | workspaceId: input.workspaceId, |
| 235 | configKey: null, | ||
| 236 | name: input.payload.name.trim(), | 235 | name: input.payload.name.trim(), |
| 237 | kind: input.payload.kind, | 236 | kind: input.payload.kind, |
| 238 | endpoint: input.payload.endpoint.trim(), | 237 | endpoint: input.payload.endpoint.trim(), |
| @@ -353,7 +352,6 @@ export const splitSourceForStorage = (input: { · 114 unmodified lines | |||
| 353 | const sourceRecord: StoredSourceRecord = { | 352 | const sourceRecord: StoredSourceRecord = { |
| 354 | id: input.source.id, | 353 | id: input.source.id, |
| 355 | workspaceId: input.source.workspaceId, | 354 | workspaceId: input.source.workspaceId, |
| 356 | configKey: input.source.configKey, | ||
| 357 | recipeId: input.recipeId, | 355 | recipeId: input.recipeId, |
| 358 | recipeRevisionId: input.recipeRevisionId, | 356 | recipeRevisionId: input.recipeRevisionId, |
| 359 | name: input.source.name, | 357 | name: input.source.name, |
| @@ -408,7 +406,6 @@ export const projectSourceFromStorage = (input: { · 48 unmodified lines | |||
| 408 | return { | 406 | return { |
| 409 | id: input.sourceRecord.id, | 407 | id: input.sourceRecord.id, |
| 410 | workspaceId: input.sourceRecord.workspaceId, | 408 | workspaceId: input.sourceRecord.workspaceId, |
| 411 | configKey: input.sourceRecord.configKey, | ||
| 412 | name: input.sourceRecord.name, | 409 | name: input.sourceRecord.name, |
| 413 | kind: input.sourceRecord.kind, | 410 | kind: input.sourceRecord.kind, |
| 414 | endpoint: input.sourceRecord.endpoint, | 411 | endpoint: input.sourceRecord.endpoint, |
| @@ -62,7 +62,6 @@ const makeSource = (input: { · 61 unmodified lines | |||
| 62 | }): Source => ({ | 62 | }): Source => ({ |
| 63 | id: input.sourceId, | 63 | id: input.sourceId, |
| 64 | workspaceId: input.workspaceId, | 64 | workspaceId: input.workspaceId, |
| 65 | configKey: null, | ||
| 66 | name: "Cloudflare API", | 65 | name: "Cloudflare API", |
| 67 | kind: "openapi", | 66 | kind: "openapi", |
| 68 | endpoint: "https://api.cloudflare.com/client/v4", | 67 | endpoint: "https://api.cloudflare.com/client/v4", |
| @@ -238,7 +237,6 @@ describe("source-inspection", () => { · 169 unmodified lines | |||
| 238 | await Effect.runPromise(persistence.rows.sources.insert({ | 237 | await Effect.runPromise(persistence.rows.sources.insert({ |
| 239 | id: sourceId, | 238 | id: sourceId, |
| 240 | workspaceId, | 239 | workspaceId, |
| 241 | configKey: null, | ||
| 242 | recipeId, | 240 | recipeId, |
| 243 | recipeRevisionId, | 241 | recipeRevisionId, |
| 244 | name: "Cloudflare API", | 242 | name: "Cloudflare API", |
| @@ -47,7 +47,6 @@ export const syncSourceMaterialization = (input: { · 46 unmodified lines | |||
| 47 | if ( | 47 | if ( |
| 48 | runtimeLocalWorkspace !== null | 48 | runtimeLocalWorkspace !== null |
| 49 | && runtimeLocalWorkspace.installation.workspaceId === input.source.workspaceId | 49 | && runtimeLocalWorkspace.installation.workspaceId === input.source.workspaceId |
| 50 | && input.source.configKey !== null | ||
| 51 | ) { | 50 | ) { |
| 52 | if (!shouldIndexSource(input.source)) { | 51 | if (!shouldIndexSource(input.source)) { |
| 53 | const state = yield* Effect.tryPromise({ | 52 | const state = yield* Effect.tryPromise({ |
| @@ -55,13 +54,12 @@ export const syncSourceMaterialization = (input: { · 1 unmodified line | |||
| 55 | catch: (cause) => | 54 | catch: (cause) => |
| 56 | cause instanceof Error ? cause : new Error(String(cause)), | 55 | cause instanceof Error ? cause : new Error(String(cause)), |
| 57 | }); | 56 | }); |
| 58 | const existingSourceState = state.sources[input.source.configKey]; | 57 | const existingSourceState = state.sources[input.source.id]; |
| 59 | const nextState: LocalWorkspaceState = { | 58 | const nextState: LocalWorkspaceState = { |
| 60 | ...state, | 59 | ...state, |
| 61 | sources: { | 60 | sources: { |
| 62 | ...state.sources, | 61 | ...state.sources, |
| 63 | [input.source.configKey]: { | 62 | [input.source.id]: { |
| 64 | id: input.source.id, | ||
| 65 | status: (input.source.enabled ? input.source.status : "draft") as SourceStatus, | 63 | status: (input.source.enabled ? input.source.status : "draft") as SourceStatus, |
| 66 | lastError: null, | 64 | lastError: null, |
| 67 | sourceHash: input.source.sourceHash, | 65 | sourceHash: input.source.sourceHash, |
| @@ -100,10 +98,9 @@ export const syncSourceMaterialization = (input: { · 32 unmodified lines | |||
| 100 | try: () => | 98 | try: () => |
| 101 | writeLocalSourceArtifact({ | 99 | writeLocalSourceArtifact({ |
| 102 | context: runtimeLocalWorkspace.context, | 100 | context: runtimeLocalWorkspace.context, |
| 103 | configKey: input.source.configKey!, | 101 | sourceId: input.source.id, |
| 104 | artifact: buildLocalSourceArtifact({ | 102 | artifact: buildLocalSourceArtifact({ |
| 105 | source: input.source, | 103 | source: input.source, |
| 106 | configKey: input.source.configKey!, | ||
| 107 | materialization, | 104 | materialization, |
| 108 | }), | 105 | }), |
| 109 | }), | 106 | }), |
| @@ -116,13 +113,12 @@ export const syncSourceMaterialization = (input: { · 6 unmodified lines | |||
| 116 | catch: (cause) => | 113 | catch: (cause) => |
| 117 | cause instanceof Error ? cause : new Error(String(cause)), | 114 | cause instanceof Error ? cause : new Error(String(cause)), |
| 118 | }); | 115 | }); |
| 119 | const existingSourceState = state.sources[input.source.configKey]; | 116 | const existingSourceState = state.sources[input.source.id]; |
| 120 | const nextState: LocalWorkspaceState = { | 117 | const nextState: LocalWorkspaceState = { |
| 121 | ...state, | 118 | ...state, |
| 122 | sources: { | 119 | sources: { |
| 123 | ...state.sources, | 120 | ...state.sources, |
| 124 | [input.source.configKey]: { | 121 | [input.source.id]: { |
| 125 | id: input.source.id, | ||
| 126 | status: "connected", | 122 | status: "connected", |
| 127 | lastError: null, | 123 | lastError: null, |
| 128 | sourceHash: materialization.sourceHash, | 124 | sourceHash: materialization.sourceHash, |
| @@ -179,7 +175,6 @@ export const persistMcpRecipeMaterializationFromManifest = (input: { · 50 unmodified lines | |||
| 179 | if ( | 175 | if ( |
| 180 | runtimeLocalWorkspace !== null | 176 | runtimeLocalWorkspace !== null |
| 181 | && runtimeLocalWorkspace.installation.workspaceId === input.source.workspaceId | 177 | && runtimeLocalWorkspace.installation.workspaceId === input.source.workspaceId |
| 182 | && input.source.configKey !== null | ||
| 183 | ) { | 178 | ) { |
| 184 | const materialization = materializationFromMcpManifestEntries({ | 179 | const materialization = materializationFromMcpManifestEntries({ |
| 185 | recipeRevisionId: "src_recipe_rev_materialization" as never, | 180 | recipeRevisionId: "src_recipe_rev_materialization" as never, |
| @@ -191,10 +186,9 @@ export const persistMcpRecipeMaterializationFromManifest = (input: { · 5 unmodified lines | |||
| 191 | try: () => | 186 | try: () => |
| 192 | writeLocalSourceArtifact({ | 187 | writeLocalSourceArtifact({ |
| 193 | context: runtimeLocalWorkspace.context, | 188 | context: runtimeLocalWorkspace.context, |
| 194 | configKey: input.source.configKey!, | 189 | sourceId: input.source.id, |
| 195 | artifact: buildLocalSourceArtifact({ | 190 | artifact: buildLocalSourceArtifact({ |
| 196 | source: input.source, | 191 | source: input.source, |
| 197 | configKey: input.source.configKey!, | ||
| 198 | materialization, | 192 | materialization, |
| 199 | }), | 193 | }), |
| 200 | }), | 194 | }), |
| @@ -87,7 +87,6 @@ const makeSource = (overrides: Partial<Source> = {}): Source => { · 86 unmodified lines | |||
| 87 | return { | 87 | return { |
| 88 | id: SourceIdSchema.make("src_runtime_recipe"), | 88 | id: SourceIdSchema.make("src_runtime_recipe"), |
| 89 | workspaceId: WorkspaceIdSchema.make("ws_runtime_recipe"), | 89 | workspaceId: WorkspaceIdSchema.make("ws_runtime_recipe"), |
| 90 | configKey: null, | ||
| 91 | name: "GitHub", | 90 | name: "GitHub", |
| 92 | kind, | 91 | kind, |
| 93 | endpoint, | 92 | endpoint, |
| @@ -373,7 +372,6 @@ describe("source-recipes-runtime", () => { · 279 unmodified lines | |||
| 373 | sourceRecord: { | 372 | sourceRecord: { |
| 374 | id: SourceIdSchema.make("src_runtime_recipe"), | 373 | id: SourceIdSchema.make("src_runtime_recipe"), |
| 375 | workspaceId: WorkspaceIdSchema.make("ws_runtime_recipe"), | 374 | workspaceId: WorkspaceIdSchema.make("ws_runtime_recipe"), |
| 376 | configKey: null, | ||
| 377 | recipeId: SourceRecipeIdSchema.make("src_recipe_runtime"), | 375 | recipeId: SourceRecipeIdSchema.make("src_recipe_runtime"), |
| 378 | recipeRevisionId: SourceRecipeRevisionIdSchema.make("src_recipe_rev_runtime"), | 376 | recipeRevisionId: SourceRecipeRevisionIdSchema.make("src_recipe_rev_runtime"), |
| 379 | name: "GITHUB API", | 377 | name: "GITHUB API", |
| @@ -545,7 +543,6 @@ describe("source-recipes-runtime", () => { · 165 unmodified lines | |||
| 545 | await Effect.runPromise(persistence.rows.sources.insert({ | 543 | await Effect.runPromise(persistence.rows.sources.insert({ |
| 546 | id: SourceIdSchema.make(`src_shared_revision_${index}`), | 544 | id: SourceIdSchema.make(`src_shared_revision_${index}`), |
| 547 | workspaceId, | 545 | workspaceId, |
| 548 | configKey: null, | ||
| 549 | recipeId, | 546 | recipeId, |
| 550 | recipeRevisionId, | 547 | recipeRevisionId, |
| 551 | name, | 548 | name, |
| @@ -624,7 +621,6 @@ describe("source-recipes-runtime", () => { · 72 unmodified lines | |||
| 624 | await Effect.runPromise(persistence.rows.sources.insert({ | 621 | await Effect.runPromise(persistence.rows.sources.insert({ |
| 625 | id: sourceId, | 622 | id: sourceId, |
| 626 | workspaceId, | 623 | workspaceId, |
| 627 | configKey: null, | ||
| 628 | recipeId, | 624 | recipeId, |
| 629 | recipeRevisionId, | 625 | recipeRevisionId, |
| 630 | name: "GraphQL Demo", | 626 | name: "GraphQL Demo", |
| @@ -692,7 +688,6 @@ describe("source-recipes-runtime", () => { · 61 unmodified lines | |||
| 692 | await Effect.runPromise(persistence.rows.sources.insert({ | 688 | await Effect.runPromise(persistence.rows.sources.insert({ |
| 693 | id: sourceId, | 689 | id: sourceId, |
| 694 | workspaceId, | 690 | workspaceId, |
| 695 | configKey: null, | ||
| 696 | recipeId, | 691 | recipeId, |
| 697 | recipeRevisionId, | 692 | recipeRevisionId, |
| 698 | name: "Broken GitHub", | 693 | name: "Broken GitHub", |
| @@ -173,15 +173,11 @@ export const loadWorkspaceSourceRecipes = (input: { · 172 unmodified lines | |||
| 173 | 173 | ||
| 174 | const localRecipes = yield* Effect.forEach(sources, (source) => | 174 | const localRecipes = yield* Effect.forEach(sources, (source) => |
| 175 | Effect.gen(function* () { | 175 | Effect.gen(function* () { |
| 176 | if (source.configKey === null) { | ||
| 177 | return null; | ||
| 178 | } | ||
| 179 | |||
| 180 | const artifact = yield* Effect.tryPromise({ | 176 | const artifact = yield* Effect.tryPromise({ |
| 181 | try: () => | 177 | try: () => |
| 182 | readLocalSourceArtifact({ | 178 | readLocalSourceArtifact({ |
| 183 | context: runtimeLocalWorkspace.context, | 179 | context: runtimeLocalWorkspace.context, |
| 184 | configKey: source.configKey!, | 180 | sourceId: source.id, |
| 185 | }), | 181 | }), |
| 186 | catch: (cause) => | 182 | catch: (cause) => |
| 187 | cause instanceof Error ? cause : new Error(String(cause)), | 183 | cause instanceof Error ? cause : new Error(String(cause)), |
| @@ -193,7 +189,6 @@ export const loadWorkspaceSourceRecipes = (input: { · 5 unmodified lines | |||
| 193 | const sourceRecord: StoredSourceRecord = { | 189 | const sourceRecord: StoredSourceRecord = { |
| 194 | id: source.id, | 190 | id: source.id, |
| 195 | workspaceId: source.workspaceId, | 191 | workspaceId: source.workspaceId, |
| 196 | configKey: source.configKey, | ||
| 197 | recipeId: artifact.recipeId, | 192 | recipeId: artifact.recipeId, |
| 198 | recipeRevisionId: artifact.revision.id, | 193 | recipeRevisionId: artifact.revision.id, |
| 199 | name: source.name, | 194 | name: source.name, |
| @@ -313,17 +308,12 @@ export const loadSourceWithRecipe = (input: { · 113 unmodified lines | |||
| 313 | sourceId: input.sourceId, | 308 | sourceId: input.sourceId, |
| 314 | actorAccountId: input.actorAccountId, | 309 | actorAccountId: input.actorAccountId, |
| 315 | }); | 310 | }); |
| 316 | if (source.configKey === null) { | ||
| 317 | return yield* Effect.fail( | ||
| 318 | new Error(`Source not found: workspaceId=${input.workspaceId} sourceId=${input.sourceId}`), | ||
| 319 | ); | ||
| 320 | } | ||
| 321 | 311 | ||
| 322 | const artifact = yield* Effect.tryPromise({ | 312 | const artifact = yield* Effect.tryPromise({ |
| 323 | try: () => | 313 | try: () => |
| 324 | readLocalSourceArtifact({ | 314 | readLocalSourceArtifact({ |
| 325 | context: runtimeLocalWorkspace.context, | 315 | context: runtimeLocalWorkspace.context, |
| 326 | configKey: source.configKey!, | 316 | sourceId: source.id, |
| 327 | }), | 317 | }), |
| 328 | catch: (cause) => | 318 | catch: (cause) => |
| 329 | cause instanceof Error ? cause : new Error(String(cause)), | 319 | cause instanceof Error ? cause : new Error(String(cause)), |
| @@ -337,7 +327,6 @@ export const loadSourceWithRecipe = (input: { · 7 unmodified lines | |||
| 337 | const sourceRecord: StoredSourceRecord = { | 327 | const sourceRecord: StoredSourceRecord = { |
| 338 | id: source.id, | 328 | id: source.id, |
| 339 | workspaceId: source.workspaceId, | 329 | workspaceId: source.workspaceId, |
| 340 | configKey: source.configKey, | ||
| 341 | recipeId: artifact.recipeId, | 330 | recipeId: artifact.recipeId, |
| 342 | recipeRevisionId: artifact.revision.id, | 331 | recipeRevisionId: artifact.revision.id, |
| 343 | name: source.name, | 332 | name: source.name, |
| @@ -52,7 +52,6 @@ const makeOpenApiSource = (input: { · 51 unmodified lines | |||
| 52 | }): Source => ({ | 52 | }): Source => ({ |
| 53 | id: input.sourceId, | 53 | id: input.sourceId, |
| 54 | workspaceId: input.workspaceId, | 54 | workspaceId: input.workspaceId, |
| 55 | configKey: null, | ||
| 56 | name: input.name ?? "GitHub", | 55 | name: input.name ?? "GitHub", |
| 57 | kind: "openapi", | 56 | kind: "openapi", |
| 58 | endpoint: input.endpoint ?? "https://api.github.com", | 57 | endpoint: input.endpoint ?? "https://api.github.com", |
| @@ -1,5 +1,3 @@ | |||
| 1 | import { createHash } from "node:crypto"; | ||
| 2 | |||
| 3 | import type { | 1 | import type { |
| 4 | AccountId, | 2 | AccountId, |
| 5 | AuthArtifact, | 3 | AuthArtifact, |
| @@ -7,10 +5,12 @@ import type { · 1 unmodified line | |||
| 7 | LocalConfigSecretInput, | 5 | LocalConfigSecretInput, |
| 8 | LocalConfigSource, | 6 | LocalConfigSource, |
| 9 | Source, | 7 | Source, |
| 8 | SourceId, | ||
| 10 | SourceRecipeId, | 9 | SourceRecipeId, |
| 11 | SourceRecipeRevisionId, | 10 | SourceRecipeRevisionId, |
| 12 | WorkspaceId, | 11 | WorkspaceId, |
| 13 | } from "#schema"; | 12 | } from "#schema"; |
| 13 | import { SourceIdSchema } from "#schema"; | ||
| 14 | import { type SqlControlPlaneRows } from "#persistence"; | 14 | import { type SqlControlPlaneRows } from "#persistence"; |
| 15 | import * as Effect from "effect/Effect"; | 15 | import * as Effect from "effect/Effect"; |
| 16 | import * as Option from "effect/Option"; | 16 | import * as Option from "effect/Option"; |
| @@ -118,24 +118,22 @@ const trimOrNull = (value: string | null | undefined): string | null => { · 101 unmodified lines | |||
| 118 | const cloneJson = <T>(value: T): T => | 118 | const cloneJson = <T>(value: T): T => |
| 119 | JSON.parse(JSON.stringify(value)) as T; | 119 | JSON.parse(JSON.stringify(value)) as T; |
| 120 | 120 | ||
| 121 | const localSourceIdForConfigKey = (input: { | 121 | const deriveLocalSourceId = ( |
| 122 | workspaceRoot: string; | 122 | source: Pick<Source, "namespace" | "name">, |
| 123 | configKey: string; | 123 | used: ReadonlySet<string>, |
| 124 | }): Source["id"] => { | 124 | ): SourceId => { |
| 125 | const hash = createHash("sha256") | ||
| 126 | .update(`${input.workspaceRoot}:${input.configKey}`) | ||
| 127 | .digest("hex") | ||
| 128 | .slice(0, 16); | ||
| 129 | return `src_local_${hash}` as Source["id"]; | ||
| 130 | }; | ||
| 131 | |||
| 132 | const deriveLocalSourceConfigKey = (source: Pick<Source, "configKey" | "namespace" | "name">): string => { | ||
| 133 | const base = | 125 | const base = |
| 134 | trimOrNull(source.configKey) | 126 | trimOrNull(source.namespace) |
| 135 | ?? trimOrNull(source.namespace) | ||
| 136 | ?? trimOrNull(source.name) | 127 | ?? trimOrNull(source.name) |
| 137 | ?? "source"; | 128 | ?? "source"; |
| 138 | return slugify(base) || "source"; | 129 | const slugBase = slugify(base) || "source"; |
| 130 | let candidate = slugBase; | ||
| 131 | let counter = 2; | ||
| 132 | while (used.has(candidate)) { | ||
| 133 | candidate = `${slugBase}-${counter}`; | ||
| 134 | counter += 1; | ||
| 135 | } | ||
| 136 | return SourceIdSchema.make(candidate); | ||
| 139 | }; | 137 | }; |
| 140 | 138 | ||
| 141 | const resolveLocalConfigSecretProviderAlias = (config: Awaited<ReturnType<typeof loadLocalExecutorConfig>>["config"]): string | null => { | 139 | const resolveLocalConfigSecretProviderAlias = (config: Awaited<ReturnType<typeof loadLocalExecutorConfig>>["config"]): string | null => { |
| @@ -257,34 +255,30 @@ const buildLocalSourceRecord = (input: { · 115 unmodified lines | |||
| 257 | workspaceId: WorkspaceId; | 255 | workspaceId: WorkspaceId; |
| 258 | loadedConfig: Awaited<ReturnType<typeof loadLocalExecutorConfig>>; | 256 | loadedConfig: Awaited<ReturnType<typeof loadLocalExecutorConfig>>; |
| 259 | workspaceState: LocalWorkspaceState; | 257 | workspaceState: LocalWorkspaceState; |
| 260 | configKey: string; | 258 | sourceId: SourceId; |
| 261 | actorAccountId?: AccountId | null; | 259 | actorAccountId?: AccountId | null; |
| 262 | authArtifacts: ReadonlyArray<AuthArtifact>; | 260 | authArtifacts: ReadonlyArray<AuthArtifact>; |
| 263 | }): Effect.Effect<{ | 261 | }): Effect.Effect<{ |
| 264 | source: Source; | 262 | source: Source; |
| 265 | configKey: string; | 263 | sourceId: SourceId; |
| 266 | }, Error, never> => | 264 | }, Error, never> => |
| 267 | Effect.gen(function* () { | 265 | Effect.gen(function* () { |
| 268 | const sourceConfig = input.loadedConfig.config?.sources?.[input.configKey]; | 266 | const sourceConfig = input.loadedConfig.config?.sources?.[input.sourceId]; |
| 269 | if (!sourceConfig) { | 267 | if (!sourceConfig) { |
| 270 | return yield* Effect.fail(new Error(`Configured source not found for key ${input.configKey}`)); | 268 | return yield* Effect.fail(new Error(`Configured source not found for id ${input.sourceId}`)); |
| 271 | } | 269 | } |
| 272 | 270 | ||
| 273 | const existingState = input.workspaceState.sources[input.configKey]; | 271 | const existingState = input.workspaceState.sources[input.sourceId]; |
| 274 | const adapter = getSourceAdapter(sourceConfig.kind); | 272 | const adapter = getSourceAdapter(sourceConfig.kind); |
| 275 | const baseSource = yield* adapter.validateSource({ | 273 | const baseSource = yield* adapter.validateSource({ |
| 276 | id: existingState?.id ?? localSourceIdForConfigKey({ | 274 | id: SourceIdSchema.make(input.sourceId), |
| 277 | workspaceRoot: input.context.workspaceRoot, | ||
| 278 | configKey: input.configKey, | ||
| 279 | }), | ||
| 280 | workspaceId: input.workspaceId, | 275 | workspaceId: input.workspaceId, |
| 281 | configKey: input.configKey, | 276 | name: trimOrNull(sourceConfig.name) ?? input.sourceId, |
| 282 | name: trimOrNull(sourceConfig.name) ?? input.configKey, | ||
| 283 | kind: sourceConfig.kind, | 277 | kind: sourceConfig.kind, |
| 284 | endpoint: sourceConfig.connection.endpoint.trim(), | 278 | endpoint: sourceConfig.connection.endpoint.trim(), |
| 285 | status: existingState?.status ?? ((sourceConfig.enabled ?? true) ? "connected" : "draft"), | 279 | status: existingState?.status ?? ((sourceConfig.enabled ?? true) ? "connected" : "draft"), |
| 286 | enabled: sourceConfig.enabled ?? true, | 280 | enabled: sourceConfig.enabled ?? true, |
| 287 | namespace: trimOrNull(sourceConfig.namespace) ?? input.configKey, | 281 | namespace: trimOrNull(sourceConfig.namespace) ?? input.sourceId, |
| 288 | bindingVersion: adapter.bindingConfigVersion, | 282 | bindingVersion: adapter.bindingConfigVersion, |
| 289 | binding: sourceConfig.binding, | 283 | binding: sourceConfig.binding, |
| 290 | importAuthPolicy: adapter.defaultImportAuthPolicy, | 284 | importAuthPolicy: adapter.defaultImportAuthPolicy, |
| @@ -303,7 +297,7 @@ const buildLocalSourceRecord = (input: { · 12 unmodified lines | |||
| 303 | const artifact = yield* Effect.tryPromise({ | 297 | const artifact = yield* Effect.tryPromise({ |
| 304 | try: () => readLocalSourceArtifact({ | 298 | try: () => readLocalSourceArtifact({ |
| 305 | context: input.context, | 299 | context: input.context, |
| 306 | configKey: input.configKey, | 300 | sourceId: input.sourceId, |
| 307 | }), | 301 | }), |
| 308 | catch: (cause) => | 302 | catch: (cause) => |
| 309 | cause instanceof Error ? cause : new Error(String(cause)), | 303 | cause instanceof Error ? cause : new Error(String(cause)), |
| @@ -325,7 +319,6 @@ const buildLocalSourceRecord = (input: { · 15 unmodified lines | |||
| 325 | const sourceRecord = { | 319 | const sourceRecord = { |
| 326 | id: baseSource.id, | 320 | id: baseSource.id, |
| 327 | workspaceId: baseSource.workspaceId, | 321 | workspaceId: baseSource.workspaceId, |
| 328 | configKey: input.configKey, | ||
| 329 | recipeId: artifact?.recipeId ?? stableSourceRecipeId(baseSource), | 322 | recipeId: artifact?.recipeId ?? stableSourceRecipeId(baseSource), |
| 330 | recipeRevisionId: artifact?.revision.id ?? stableSourceRecipeRevisionId(baseSource), | 323 | recipeRevisionId: artifact?.revision.id ?? stableSourceRecipeRevisionId(baseSource), |
| 331 | name: baseSource.name, | 324 | name: baseSource.name, |
| @@ -350,39 +343,10 @@ const buildLocalSourceRecord = (input: { · 18 unmodified lines | |||
| 350 | 343 | ||
| 351 | return { | 344 | return { |
| 352 | source, | 345 | source, |
| 353 | configKey: input.configKey, | 346 | sourceId: input.sourceId, |
| 354 | }; | 347 | }; |
| 355 | }); | 348 | }); |
| 356 | 349 | ||
| 357 | const resolveLocalSourceConfigKey = (input: { | ||
| 358 | context: { | ||
| 359 | workspaceRoot: string; | ||
| 360 | }; | ||
| 361 | loadedConfig: Awaited<ReturnType<typeof loadLocalExecutorConfig>>; | ||
| 362 | workspaceState: LocalWorkspaceState; | ||
| 363 | sourceId: Source["id"]; | ||
| 364 | }): string | null => { | ||
| 365 | const configKeys = Object.keys(input.loadedConfig.config?.sources ?? {}); | ||
| 366 | for (const configKey of configKeys) { | ||
| 367 | const storedId = input.workspaceState.sources[configKey]?.id; | ||
| 368 | if (storedId === input.sourceId) { | ||
| 369 | return configKey; | ||
| 370 | } | ||
| 371 | |||
| 372 | if ( | ||
| 373 | storedId === undefined | ||
| 374 | && localSourceIdForConfigKey({ | ||
| 375 | workspaceRoot: input.context.workspaceRoot, | ||
| 376 | configKey, | ||
| 377 | }) === input.sourceId | ||
| 378 | ) { | ||
| 379 | return configKey; | ||
| 380 | } | ||
| 381 | } | ||
| 382 | |||
| 383 | return null; | ||
| 384 | }; | ||
| 385 | |||
| 386 | export const loadSourcesInWorkspace = ( | 350 | export const loadSourcesInWorkspace = ( |
| 387 | rows: SqlControlPlaneRows, | 351 | rows: SqlControlPlaneRows, |
| 388 | workspaceId: WorkspaceId, | 352 | workspaceId: WorkspaceId, |
| @@ -396,14 +360,14 @@ export const loadSourcesInWorkspace = ( · 7 unmodified lines | |||
| 396 | const authArtifacts = yield* rows.authArtifacts.listByWorkspaceId(workspaceId); | 360 | const authArtifacts = yield* rows.authArtifacts.listByWorkspaceId(workspaceId); |
| 397 | return yield* Effect.forEach( | 361 | return yield* Effect.forEach( |
| 398 | Object.keys(localWorkspace.loadedConfig.config?.sources ?? {}), | 362 | Object.keys(localWorkspace.loadedConfig.config?.sources ?? {}), |
| 399 | (configKey) => | 363 | (sourceId) => |
| 400 | Effect.map( | 364 | Effect.map( |
| 401 | buildLocalSourceRecord({ | 365 | buildLocalSourceRecord({ |
| 402 | context: localWorkspace.context, | 366 | context: localWorkspace.context, |
| 403 | workspaceId, | 367 | workspaceId, |
| 404 | loadedConfig: localWorkspace.loadedConfig, | 368 | loadedConfig: localWorkspace.loadedConfig, |
| 405 | workspaceState: localWorkspace.workspaceState, | 369 | workspaceState: localWorkspace.workspaceState, |
| 406 | configKey, | 370 | sourceId: SourceIdSchema.make(sourceId), |
| 407 | actorAccountId: options.actorAccountId, | 371 | actorAccountId: options.actorAccountId, |
| 408 | authArtifacts, | 372 | authArtifacts, |
| 409 | }), | 373 | }), |
| @@ -446,14 +410,7 @@ export const loadSourceById = (rows: SqlControlPlaneRows, input: { · 36 unmodified lines | |||
| 446 | const localWorkspace = yield* resolveRuntimeLocalWorkspace(input.workspaceId); | 410 | const localWorkspace = yield* resolveRuntimeLocalWorkspace(input.workspaceId); |
| 447 | if (localWorkspace !== null) { | 411 | if (localWorkspace !== null) { |
| 448 | const authArtifacts = yield* rows.authArtifacts.listByWorkspaceId(input.workspaceId); | 412 | const authArtifacts = yield* rows.authArtifacts.listByWorkspaceId(input.workspaceId); |
| 449 | const configKey = resolveLocalSourceConfigKey({ | 413 | if (!localWorkspace.loadedConfig.config?.sources?.[input.sourceId]) { |
| 450 | context: localWorkspace.context, | ||
| 451 | loadedConfig: localWorkspace.loadedConfig, | ||
| 452 | workspaceState: localWorkspace.workspaceState, | ||
| 453 | sourceId: input.sourceId, | ||
| 454 | }); | ||
| 455 | |||
| 456 | if (configKey === null) { | ||
| 457 | return yield* Effect.fail( | 414 | return yield* Effect.fail( |
| 458 | new Error(`Source not found: workspaceId=${input.workspaceId} sourceId=${input.sourceId}`), | 415 | new Error(`Source not found: workspaceId=${input.workspaceId} sourceId=${input.sourceId}`), |
| 459 | ); | 416 | ); |
| @@ -464,7 +421,7 @@ export const loadSourceById = (rows: SqlControlPlaneRows, input: { · 4 unmodified lines | |||
| 464 | workspaceId: input.workspaceId, | 421 | workspaceId: input.workspaceId, |
| 465 | loadedConfig: localWorkspace.loadedConfig, | 422 | loadedConfig: localWorkspace.loadedConfig, |
| 466 | workspaceState: localWorkspace.workspaceState, | 423 | workspaceState: localWorkspace.workspaceState, |
| 467 | configKey, | 424 | sourceId: input.sourceId, |
| 468 | actorAccountId: input.actorAccountId, | 425 | actorAccountId: input.actorAccountId, |
| 469 | authArtifacts, | 426 | authArtifacts, |
| 470 | }); | 427 | }); |
| @@ -507,7 +464,6 @@ export const loadSourceById = (rows: SqlControlPlaneRows, input: { · 36 unmodified lines | |||
| 507 | 464 | ||
| 508 | const configSourceFromLocalSource = (input: { | 465 | const configSourceFromLocalSource = (input: { |
| 509 | source: Source; | 466 | source: Source; |
| 510 | configKey: string; | ||
| 511 | existingConfigAuth: LocalConfigSecretInput | undefined; | 467 | existingConfigAuth: LocalConfigSecretInput | undefined; |
| 512 | config: Awaited<ReturnType<typeof loadLocalExecutorConfig>>["config"]; | 468 | config: Awaited<ReturnType<typeof loadLocalExecutorConfig>>["config"]; |
| 513 | }): LocalConfigSource => { | 469 | }): LocalConfigSource => { |
| @@ -518,10 +474,10 @@ const configSourceFromLocalSource = (input: { · 4 unmodified lines | |||
| 518 | }); | 474 | }); |
| 519 | 475 | ||
| 520 | const common = { | 476 | const common = { |
| 521 | ...(trimOrNull(input.source.name) !== trimOrNull(input.configKey) | 477 | ...(trimOrNull(input.source.name) !== trimOrNull(input.source.id) |
| 522 | ? { name: input.source.name } | 478 | ? { name: input.source.name } |
| 523 | : {}), | 479 | : {}), |
| 524 | ...(trimOrNull(input.source.namespace) !== trimOrNull(input.configKey) | 480 | ...(trimOrNull(input.source.namespace) !== trimOrNull(input.source.id) |
| 525 | ? { namespace: input.source.namespace ?? undefined } | 481 | ? { namespace: input.source.namespace ?? undefined } |
| 526 | : {}), | 482 | : {}), |
| 527 | ...(input.source.enabled === false ? { enabled: false } : {}), | 483 | ...(input.source.enabled === false ? { enabled: false } : {}), |
| @@ -639,13 +595,7 @@ export const removeSourceById = (rows: SqlControlPlaneRows, input: { · 111 unmodified lines | |||
| 639 | Effect.gen(function* () { | 595 | Effect.gen(function* () { |
| 640 | const localWorkspace = yield* resolveRuntimeLocalWorkspace(input.workspaceId); | 596 | const localWorkspace = yield* resolveRuntimeLocalWorkspace(input.workspaceId); |
| 641 | if (localWorkspace !== null) { | 597 | if (localWorkspace !== null) { |
| 642 | const configKey = resolveLocalSourceConfigKey({ | 598 | if (!localWorkspace.loadedConfig.config?.sources?.[input.sourceId]) { |
| 643 | context: localWorkspace.context, | ||
| 644 | loadedConfig: localWorkspace.loadedConfig, | ||
| 645 | workspaceState: localWorkspace.workspaceState, | ||
| 646 | sourceId: input.sourceId, | ||
| 647 | }); | ||
| 648 | if (configKey === null) { | ||
| 649 | return false; | 599 | return false; |
| 650 | } | 600 | } |
| 651 | 601 | ||
| @@ -653,7 +603,7 @@ export const removeSourceById = (rows: SqlControlPlaneRows, input: { · 1 unmodified line | |||
| 653 | const sources = { | 603 | const sources = { |
| 654 | ...(projectConfig.sources ?? {}), | 604 | ...(projectConfig.sources ?? {}), |
| 655 | }; | 605 | }; |
| 656 | delete sources[configKey]; | 606 | delete sources[input.sourceId]; |
| 657 | yield* Effect.tryPromise({ | 607 | yield* Effect.tryPromise({ |
| 658 | try: () => | 608 | try: () => |
| 659 | writeProjectLocalExecutorConfig({ | 609 | writeProjectLocalExecutorConfig({ |
| @@ -668,7 +618,7 @@ export const removeSourceById = (rows: SqlControlPlaneRows, input: { · 8 unmodified lines | |||
| 668 | }); | 618 | }); |
| 669 | 619 | ||
| 670 | const { | 620 | const { |
| 671 | [configKey]: _removedSource, | 621 | [input.sourceId]: _removedSource, |
| 672 | ...remainingSources | 622 | ...remainingSources |
| 673 | } = localWorkspace.workspaceState.sources; | 623 | } = localWorkspace.workspaceState.sources; |
| 674 | const workspaceState: LocalWorkspaceState = { | 624 | const workspaceState: LocalWorkspaceState = { |
| @@ -688,7 +638,7 @@ export const removeSourceById = (rows: SqlControlPlaneRows, input: { · 13 unmodified lines | |||
| 688 | try: () => | 638 | try: () => |
| 689 | removeLocalSourceArtifact({ | 639 | removeLocalSourceArtifact({ |
| 690 | context: localWorkspace.context, | 640 | context: localWorkspace.context, |
| 691 | configKey, | 641 | sourceId: input.sourceId, |
| 692 | }), | 642 | }), |
| 693 | catch: (cause) => | 643 | catch: (cause) => |
| 694 | cause instanceof Error ? cause : new Error(String(cause)), | 644 | cause instanceof Error ? cause : new Error(String(cause)), |
| @@ -743,9 +693,20 @@ export const persistSource = ( · 48 unmodified lines | |||
| 743 | Effect.gen(function* () { | 693 | Effect.gen(function* () { |
| 744 | const localWorkspace = yield* resolveRuntimeLocalWorkspace(source.workspaceId); | 694 | const localWorkspace = yield* resolveRuntimeLocalWorkspace(source.workspaceId); |
| 745 | if (localWorkspace !== null) { | 695 | if (localWorkspace !== null) { |
| 696 | const nextSource = { | ||
| 697 | ...source, | ||
| 698 | id: | ||
| 699 | localWorkspace.loadedConfig.config?.sources?.[source.id] | ||
| 700 | || localWorkspace.workspaceState.sources[source.id] | ||
| 701 | ? source.id | ||
| 702 | : deriveLocalSourceId( | ||
| 703 | source, | ||
| 704 | new Set(Object.keys(localWorkspace.loadedConfig.config?.sources ?? {})), | ||
| 705 | ), | ||
| 706 | } satisfies Source; | ||
| 746 | const existingAuthArtifacts = yield* rows.authArtifacts.listByWorkspaceAndSourceId({ | 707 | const existingAuthArtifacts = yield* rows.authArtifacts.listByWorkspaceAndSourceId({ |
| 747 | workspaceId: source.workspaceId, | 708 | workspaceId: nextSource.workspaceId, |
| 748 | sourceId: source.id, | 709 | sourceId: nextSource.id, |
| 749 | }); | 710 | }); |
| 750 | const existingRuntimeAuthArtifact = selectExactAuthArtifact({ | 711 | const existingRuntimeAuthArtifact = selectExactAuthArtifact({ |
| 751 | authArtifacts: existingAuthArtifacts, | 712 | authArtifacts: existingAuthArtifacts, |
| @@ -757,27 +718,13 @@ export const persistSource = ( · 5 unmodified lines | |||
| 757 | actorAccountId: options.actorAccountId, | 718 | actorAccountId: options.actorAccountId, |
| 758 | slot: "import", | 719 | slot: "import", |
| 759 | }); | 720 | }); |
| 760 | const configKey = | ||
| 761 | source.configKey | ||
| 762 | ?? resolveLocalSourceConfigKey({ | ||
| 763 | context: localWorkspace.context, | ||
| 764 | loadedConfig: localWorkspace.loadedConfig, | ||
| 765 | workspaceState: localWorkspace.workspaceState, | ||
| 766 | sourceId: source.id, | ||
| 767 | }) | ||
| 768 | ?? deriveLocalSourceConfigKey(source); | ||
| 769 | const nextSource = { | ||
| 770 | ...source, | ||
| 771 | configKey, | ||
| 772 | } satisfies Source; | ||
| 773 | const projectConfig = cloneJson(localWorkspace.loadedConfig.projectConfig ?? {}); | 721 | const projectConfig = cloneJson(localWorkspace.loadedConfig.projectConfig ?? {}); |
| 774 | const sources = { | 722 | const sources = { |
| 775 | ...(projectConfig.sources ?? {}), | 723 | ...(projectConfig.sources ?? {}), |
| 776 | }; | 724 | }; |
| 777 | const existingConfigSource = sources[configKey]; | 725 | const existingConfigSource = sources[nextSource.id]; |
| 778 | sources[configKey] = configSourceFromLocalSource({ | 726 | sources[nextSource.id] = configSourceFromLocalSource({ |
| 779 | source: nextSource, | 727 | source: nextSource, |
| 780 | configKey, | ||
| 781 | existingConfigAuth: existingConfigSource?.connection.auth, | 728 | existingConfigAuth: existingConfigSource?.connection.auth, |
| 782 | config: localWorkspace.loadedConfig.config, | 729 | config: localWorkspace.loadedConfig.config, |
| 783 | }); | 730 | }); |
| @@ -810,8 +757,8 @@ export const persistSource = ( · 26 unmodified lines | |||
| 810 | }); | 757 | }); |
| 811 | } | 758 | } |
| 812 | yield* rows.authArtifacts.removeByWorkspaceSourceAndActor({ | 759 | yield* rows.authArtifacts.removeByWorkspaceSourceAndActor({ |
| 813 | workspaceId: source.workspaceId, | 760 | workspaceId: nextSource.workspaceId, |
| 814 | sourceId: source.id, | 761 | sourceId: nextSource.id, |
| 815 | actorAccountId: options.actorAccountId ?? null, | 762 | actorAccountId: options.actorAccountId ?? null, |
| 816 | slot: "runtime", | 763 | slot: "runtime", |
| 817 | }); | 764 | }); |
| @@ -839,8 +786,8 @@ export const persistSource = ( · 21 unmodified lines | |||
| 839 | }); | 786 | }); |
| 840 | } | 787 | } |
| 841 | yield* rows.authArtifacts.removeByWorkspaceSourceAndActor({ | 788 | yield* rows.authArtifacts.removeByWorkspaceSourceAndActor({ |
| 842 | workspaceId: source.workspaceId, | 789 | workspaceId: nextSource.workspaceId, |
| 843 | sourceId: source.id, | 790 | sourceId: nextSource.id, |
| 844 | actorAccountId: options.actorAccountId ?? null, | 791 | actorAccountId: options.actorAccountId ?? null, |
| 845 | slot: "import", | 792 | slot: "import", |
| 846 | }); | 793 | }); |
| @@ -861,13 +808,12 @@ export const persistSource = ( · 14 unmodified lines | |||
| 861 | next: importAuthArtifact, | 808 | next: importAuthArtifact, |
| 862 | }); | 809 | }); |
| 863 | 810 | ||
| 864 | const existingSourceState = localWorkspace.workspaceState.sources[configKey]; | 811 | const existingSourceState = localWorkspace.workspaceState.sources[nextSource.id]; |
| 865 | const workspaceState: LocalWorkspaceState = { | 812 | const workspaceState: LocalWorkspaceState = { |
| 866 | ...localWorkspace.workspaceState, | 813 | ...localWorkspace.workspaceState, |
| 867 | sources: { | 814 | sources: { |
| 868 | ...localWorkspace.workspaceState.sources, | 815 | ...localWorkspace.workspaceState.sources, |
| 869 | [configKey]: { | 816 | [nextSource.id]: { |
| 870 | id: nextSource.id, | ||
| 871 | status: nextSource.status, | 817 | status: nextSource.status, |
| 872 | lastError: nextSource.lastError, | 818 | lastError: nextSource.lastError, |
| 873 | sourceHash: nextSource.sourceHash, | 819 | sourceHash: nextSource.sourceHash, |
| @@ -589,7 +589,6 @@ const persistConnectedEchoTool = (input: { · 588 unmodified lines | |||
| 589 | const source: Source = { | 589 | const source: Source = { |
| 590 | id: input.sourceId, | 590 | id: input.sourceId, |
| 591 | workspaceId: input.workspaceId, | 591 | workspaceId: input.workspaceId, |
| 592 | configKey: null, | ||
| 593 | name: "Counted MCP", | 592 | name: "Counted MCP", |
| 594 | kind: "mcp", | 593 | kind: "mcp", |
| 595 | endpoint: input.endpoint, | 594 | endpoint: input.endpoint, |
| @@ -802,7 +801,6 @@ const persistConnectedGithubOpenApiSource = (input: { · 206 unmodified lines | |||
| 802 | const source: Source = { | 801 | const source: Source = { |
| 803 | id: input.sourceId, | 802 | id: input.sourceId, |
| 804 | workspaceId: input.workspaceId, | 803 | workspaceId: input.workspaceId, |
| 805 | configKey: null, | ||
| 806 | name: "GitHub", | 804 | name: "GitHub", |
| 807 | kind: "openapi", | 805 | kind: "openapi", |
| 808 | endpoint: input.endpoint ?? "https://api.github.com", | 806 | endpoint: input.endpoint ?? "https://api.github.com", |
| @@ -97,7 +97,6 @@ export const StoredSourceRecordSchema = Schema.transform( · 96 unmodified lines | |||
| 97 | Schema.Struct({ | 97 | Schema.Struct({ |
| 98 | id: SourceIdSchema, | 98 | id: SourceIdSchema, |
| 99 | workspaceId: WorkspaceIdSchema, | 99 | workspaceId: WorkspaceIdSchema, |
| 100 | configKey: Schema.NullOr(Schema.String), | ||
| 101 | recipeId: SourceRecipeIdSchema, | 100 | recipeId: SourceRecipeIdSchema, |
| 102 | recipeRevisionId: SourceRecipeRevisionIdSchema, | 101 | recipeRevisionId: SourceRecipeRevisionIdSchema, |
| 103 | name: Schema.String, | 102 | name: Schema.String, |
| @@ -118,7 +117,6 @@ export const StoredSourceRecordSchema = Schema.transform( · 14 unmodified lines | |||
| 118 | decode: (row, _input) => ({ | 117 | decode: (row, _input) => ({ |
| 119 | id: row.sourceId, | 118 | id: row.sourceId, |
| 120 | workspaceId: row.workspaceId, | 119 | workspaceId: row.workspaceId, |
| 121 | configKey: null, | ||
| 122 | recipeId: row.recipeId, | 120 | recipeId: row.recipeId, |
| 123 | recipeRevisionId: row.recipeRevisionId, | 121 | recipeRevisionId: row.recipeRevisionId, |
| 124 | name: row.name, | 122 | name: row.name, |
| @@ -158,7 +156,6 @@ export const StoredSourceRecordSchema = Schema.transform( · 33 unmodified lines | |||
| 158 | export const SourceSchema = Schema.Struct({ | 156 | export const SourceSchema = Schema.Struct({ |
| 159 | id: SourceIdSchema, | 157 | id: SourceIdSchema, |
| 160 | workspaceId: WorkspaceIdSchema, | 158 | workspaceId: WorkspaceIdSchema, |
| 161 | configKey: Schema.NullOr(Schema.String), | ||
| 162 | name: Schema.String, | 159 | name: Schema.String, |
| 163 | kind: SourceKindSchema, | 160 | kind: SourceKindSchema, |
| 164 | endpoint: Schema.String, | 161 | endpoint: Schema.String, |
| @@ -492,7 +492,6 @@ const openApiSource = (input: { · 491 unmodified lines | |||
| 492 | }): Source => ({ | 492 | }): Source => ({ |
| 493 | id: input.sourceId, | 493 | id: input.sourceId, |
| 494 | workspaceId: input.workspaceId, | 494 | workspaceId: input.workspaceId, |
| 495 | configKey: null, | ||
| 496 | name: input.displayName, | 495 | name: input.displayName, |
| 497 | kind: "openapi", | 496 | kind: "openapi", |
| 498 | endpoint: input.baseUrl, | 497 | endpoint: input.baseUrl, |
| @@ -661,7 +661,6 @@ const createOptimisticSource = (input: { · 660 unmodified lines | |||
| 661 | return { | 661 | return { |
| 662 | id: `src_optimistic_${crypto.randomUUID()}` as Source["id"], | 662 | id: `src_optimistic_${crypto.randomUUID()}` as Source["id"], |
| 663 | workspaceId: input.workspaceId, | 663 | workspaceId: input.workspaceId, |
| 664 | configKey: null, | ||
| 665 | name: input.payload.name, | 664 | name: input.payload.name, |
| 666 | kind: input.payload.kind, | 665 | kind: input.payload.kind, |
| 667 | endpoint: input.payload.endpoint, | 666 | endpoint: input.payload.endpoint, |