- Remove configInput parameter from toConfigSource and toConfig - Centralize iconUrl handling in scopeConfigSourceBaseFromSource - Remove configuredIconUrlFromConfigInput utility (moved to source-core) - Simplify iconUrl handling with optional chaining trim pattern - Re-export getFaviconUrlForRemoteUrl from source-core in plugin shared modules
Unified · Split
| @@ -294,7 +294,6 @@ export type ExecutorSourcePluginDefinition< · 293 unmodified lines | ||
| 294 | 294 | toConfig: (input: { |
| 295 | 295 | source: ExecutorSource; |
| 296 | 296 | stored: TStored; |
| 297 | − configSource: ExecutorScopeConfigSource | null; | |
| 298 | 297 | }) => TSourceConfig; |
| 299 | 298 | remove?: (input: { |
| 300 | 299 | source: ExecutorSource; |
| @@ -305,7 +304,6 @@ export type ExecutorSourcePluginDefinition< · 4 unmodified lines | ||
| 305 | 304 | toConfigSource: (input: { |
| 306 | 305 | source: ExecutorSource; |
| 307 | 306 | stored: TStored; |
| 308 | − configInput: TConnectInput | TSourceConfig | null; | |
| 309 | 307 | }) => ExecutorScopeConfigSource; |
| 310 | 308 | recoverStored: (input: { |
| 311 | 309 | source: ExecutorSource; |
| @@ -610,7 +608,6 @@ const persistSourceScopeConfig = < · 298 unmodified lines | ||
| 610 | 608 | input: { |
| 611 | 609 | source: ExecutorSource; |
| 612 | 610 | stored: TStored; |
| 613 | − configInput: TConnectInput | TSourceConfig | null; | |
| 614 | 611 | }, |
| 615 | 612 | ): Effect.Effect<void, Error, ScopeConfigStore> => |
| 616 | 613 | definition.scopeConfig |
| @@ -619,12 +616,12 @@ const persistSourceScopeConfig = < · 2 unmodified lines | ||
| 619 | 616 | const scopeConfigStore = yield* ScopeConfigStore; |
| 620 | 617 | const loadedConfig = yield* scopeConfigStore.load(); |
| 621 | 618 | const projectConfig = cloneJson(loadedConfig.projectConfig ?? {}); |
| 619 | + | |
| 622 | 620 | const sources = { |
| 623 | 621 | ...projectConfig.sources, |
| 624 | 622 | [input.source.id]: scopeConfig.toConfigSource({ |
| 625 | 623 | source: input.source, |
| 626 | 624 | stored: input.stored, |
| 627 | − configInput: input.configInput, | |
| 628 | 625 | }), |
| 629 | 626 | }; |
| 630 | 627 | |
| @@ -737,12 +734,12 @@ const createExecutorSourcePluginApi = < · 106 unmodified lines | ||
| 737 | 734 | |
| 738 | 735 | const scopeConfigStore = yield* ScopeConfigStore; |
| 739 | 736 | const loadedConfig = yield* scopeConfigStore.load(); |
| 737 | + const iconUrl = loadedConfig.config?.sources?.[source.id]?.iconUrl; | |
| 740 | 738 | |
| 741 | − return definition.source.toConfig({ | |
| 742 | − source, | |
| 743 | − stored, | |
| 744 | − configSource: loadedConfig.config?.sources?.[source.id] ?? null, | |
| 745 | − }); | |
| 739 | + return { | |
| 740 | + ...definition.source.toConfig({ source, stored }), | |
| 741 | + ...(iconUrl ? { iconUrl } : {}), | |
| 742 | + }; | |
| 746 | 743 | }), |
| 747 | 744 | createSource: (input) => |
| 748 | 745 | Effect.gen(function* () { |
| @@ -759,7 +756,6 @@ const createExecutorSourcePluginApi = < · 10 unmodified lines | ||
| 759 | 756 | yield* persistSourceScopeConfig(definition, { |
| 760 | 757 | source, |
| 761 | 758 | stored: created.stored, |
| 762 | − configInput: input, | |
| 763 | 759 | }); |
| 764 | 760 | |
| 765 | 761 | return yield* host.sources.refreshCatalog(source.id); |
| @@ -784,7 +780,6 @@ const createExecutorSourcePluginApi = < · 18 unmodified lines | ||
| 784 | 780 | yield* persistSourceScopeConfig(definition, { |
| 785 | 781 | source: saved, |
| 786 | 782 | stored: updated.stored, |
| 787 | − configInput: input.config, | |
| 788 | 783 | }); |
| 789 | 784 | |
| 790 | 785 | return yield* host.sources.refreshCatalog(saved.id); |
| @@ -126,9 +126,7 @@ export const normalizeSourceForCreate = (input: { · 125 unmodified lines | ||
| 126 | 126 | status: input.source.status, |
| 127 | 127 | enabled: input.source.enabled, |
| 128 | 128 | namespace: trimOrNull(input.source.namespace), |
| 129 | − ...(trimOrNull(input.source.iconUrl) | |
| 130 | − ? { iconUrl: trimOrNull(input.source.iconUrl) ?? undefined } | |
| 131 | − : {}), | |
| 129 | + ...(input.source.iconUrl?.trim() ? { iconUrl: input.source.iconUrl.trim() } : {}), | |
| 132 | 130 | createdAt: input.now, |
| 133 | 131 | updatedAt: input.now, |
| 134 | 132 | }); |
| @@ -141,9 +139,7 @@ export const normalizeSourceForSave = (input: { · 6 unmodified lines | ||
| 141 | 139 | ...input.source, |
| 142 | 140 | name: input.source.name.trim(), |
| 143 | 141 | namespace: trimOrNull(input.source.namespace), |
| 144 | − ...(trimOrNull(input.source.iconUrl) | |
| 145 | − ? { iconUrl: trimOrNull(input.source.iconUrl) ?? undefined } | |
| 146 | − : {}), | |
| 142 | + ...(input.source.iconUrl?.trim() ? { iconUrl: input.source.iconUrl.trim() } : {}), | |
| 147 | 143 | updatedAt: input.now, |
| 148 | 144 | }); |
| 149 | 145 | |
| @@ -1,18 +1,9 @@ | ||
| 1 | 1 | import { |
| 2 | 2 | getFaviconUrlForRemoteUrl, |
| 3 | + isRecord, | |
| 3 | 4 | } from "@executor/source-core"; |
| 4 | 5 | |
| 5 | −const trimOrNull = (value: string | null | undefined): string | null => { | |
| 6 | − if (value == null) { | |
| 7 | − return null; | |
| 8 | − } | |
| 9 | − | |
| 10 | − const trimmed = value.trim(); | |
| 11 | − return trimmed.length > 0 ? trimmed : null; | |
| 12 | −}; | |
| 13 | − | |
| 14 | −const isRecord = (value: unknown): value is Record<string, unknown> => | |
| 15 | − typeof value === "object" && value !== null && !Array.isArray(value); | |
| 6 | +import { trimOrNull } from "./source-store/config"; | |
| 16 | 7 | |
| 17 | 8 | export const resolveSourceIconUrl = (input: { |
| 18 | 9 | configuredIconUrl?: string | null; |
| @@ -47,6 +47,9 @@ export const scopeConfigSourceBaseFromSource = (input: { · 46 unmodified lines | ||
| 47 | 47 | ...(trimOrNull(input.source.namespace) !== trimOrNull(input.source.id) |
| 48 | 48 | ? { namespace: input.source.namespace ?? undefined } |
| 49 | 49 | : {}), |
| 50 | + ...(input.source.iconUrl?.trim() | |
| 51 | + ? { iconUrl: input.source.iconUrl.trim() } | |
| 52 | + : {}), | |
| 50 | 53 | ...(input.source.enabled === false ? { enabled: false } : {}), |
| 51 | 54 | }); |
| 52 | 55 | |
| @@ -58,8 +61,8 @@ export const scopeConfigSourceFromSource = (input: { · 5 unmodified lines | ||
| 58 | 61 | ...scopeConfigSourceBaseFromSource({ |
| 59 | 62 | source: input.source, |
| 60 | 63 | }), |
| 61 | − ...(trimOrNull(input.existingConfig?.iconUrl) | |
| 62 | − ? { iconUrl: trimOrNull(input.existingConfig?.iconUrl) ?? undefined } | |
| 64 | + ...(input.existingConfig?.iconUrl?.trim() | |
| 65 | + ? { iconUrl: input.existingConfig.iconUrl.trim() } | |
| 63 | 66 | : {}), |
| 64 | 67 | kind: input.source.kind as ExecutorScopeConfigSource["kind"], |
| 65 | 68 | ...(input.existingConfig?.config !== undefined |
| @@ -29,19 +29,10 @@ export const createPluginScopeConfigEntrySchema = < · 28 unmodified lines | ||
| 29 | 29 | export const pluginScopeConfigSourceFromConfig = <TConfig>(input: { |
| 30 | 30 | source: Source; |
| 31 | 31 | config: TConfig; |
| 32 | − iconUrl?: string | null; | |
| 33 | 32 | }): ExecutorScopeConfigSource => ({ |
| 34 | 33 | ...scopeConfigSourceBaseFromSource({ |
| 35 | 34 | source: input.source, |
| 36 | 35 | }), |
| 37 | − ...(input.iconUrl ? { iconUrl: input.iconUrl } : {}), | |
| 38 | 36 | kind: input.source.kind as ExecutorScopeConfigSource["kind"], |
| 39 | 37 | config: cloneJson(input.config), |
| 40 | 38 | }); |
| 41 | − | |
| 42 | −export const configuredIconUrlFromConfigInput = (input: unknown): string | null => | |
| 43 | − input && typeof input === "object" && "iconUrl" in input | |
| 44 | − ? (typeof input.iconUrl === "string" | |
| 45 | − ? input.iconUrl.trim() || null | |
| 46 | − : null) | |
| 47 | − : null; | |
| @@ -23,7 +23,6 @@ import { · 22 unmodified lines | ||
| 23 | 23 | } from "@executor/platform-sdk/plugins"; |
| 24 | 24 | import { |
| 25 | 25 | SecretMaterialResolverService, |
| 26 | − configuredIconUrlFromConfigInput, | |
| 27 | 26 | createPluginScopeConfigEntrySchema, |
| 28 | 27 | pluginScopeConfigSourceFromConfig, |
| 29 | 28 | provideExecutorRuntime, |
| @@ -320,10 +319,8 @@ const storedSourceDataFromInput = ( · 290 unmodified lines | ||
| 320 | 319 | const sourceConfigFromStored = ( |
| 321 | 320 | source: Source, |
| 322 | 321 | stored: GraphqlStoredSourceData, |
| 323 | − configSource: { iconUrl?: string } | null, | |
| 324 | 322 | ): GraphqlSourceConfigPayload => ({ |
| 325 | 323 | name: source.name, |
| 326 | − ...(configSource?.iconUrl ? { iconUrl: configSource.iconUrl } : {}), | |
| 327 | 324 | endpoint: stored.endpoint, |
| 328 | 325 | defaultHeaders: stored.defaultHeaders, |
| 329 | 326 | auth: stored.auth, |
| @@ -385,6 +382,7 @@ export const graphqlSdkPlugin = (options: { · 55 unmodified lines | ||
| 385 | 382 | endpoint: input.endpoint, |
| 386 | 383 | title: input.name, |
| 387 | 384 | }), |
| 385 | + ...(input.iconUrl?.trim() ? { iconUrl: input.iconUrl.trim() } : {}), | |
| 388 | 386 | }, |
| 389 | 387 | stored: storedSourceDataFromInput(input), |
| 390 | 388 | }), |
| @@ -396,18 +394,18 @@ export const graphqlSdkPlugin = (options: { · 5 unmodified lines | ||
| 396 | 394 | endpoint: config.endpoint, |
| 397 | 395 | title: config.name, |
| 398 | 396 | }), |
| 397 | + ...(config.iconUrl?.trim() ? { iconUrl: config.iconUrl.trim() } : {}), | |
| 399 | 398 | }, |
| 400 | 399 | stored: storedSourceDataFromInput(config), |
| 401 | 400 | }), |
| 402 | − toConfig: ({ source, stored, configSource }) => | |
| 403 | − sourceConfigFromStored(source, normalizeStoredSourceData(stored), configSource), | |
| 401 | + toConfig: ({ source, stored }) => | |
| 402 | + sourceConfigFromStored(source, normalizeStoredSourceData(stored)), | |
| 404 | 403 | }, |
| 405 | 404 | scopeConfig: { |
| 406 | − toConfigSource: ({ source, stored, configInput }) => | |
| 405 | + toConfigSource: ({ source, stored }) => | |
| 407 | 406 | pluginScopeConfigSourceFromConfig({ |
| 408 | 407 | source, |
| 409 | 408 | config: normalizeStoredSourceData(stored), |
| 410 | − iconUrl: configuredIconUrlFromConfigInput(configInput), | |
| 411 | 409 | }), |
| 412 | 410 | recoverStored: ({ config, loadedConfig }) => |
| 413 | 411 | graphqlStoredSourceDataFromLocalConfig({ |
| @@ -11,6 +11,7 @@ import { · 10 unmodified lines | ||
| 11 | 11 | |
| 12 | 12 | export { getFaviconUrlForRemoteUrl } from "@executor/source-core"; |
| 13 | 13 | |
| 14 | + | |
| 14 | 15 | export const GraphqlConnectionAuthSchema = Schema.Union( |
| 15 | 16 | Schema.Struct({ |
| 16 | 17 | kind: Schema.Literal("none"), |
| @@ -31,7 +31,6 @@ import { · 30 unmodified lines | ||
| 31 | 31 | defineExecutorSourcePlugin, |
| 32 | 32 | } from "@executor/platform-sdk/plugins"; |
| 33 | 33 | import { |
| 34 | − configuredIconUrlFromConfigInput, | |
| 35 | 34 | createPluginScopeConfigEntrySchema, |
| 36 | 35 | pluginScopeConfigSourceFromConfig, |
| 37 | 36 | SecretMaterialDeleterService, |
| @@ -339,10 +338,8 @@ const normalizeStoredSourceData = ( · 301 unmodified lines | ||
| 339 | 338 | const sourceConfigFromStored = ( |
| 340 | 339 | source: Source, |
| 341 | 340 | stored: McpStoredSourceData, |
| 342 | − configSource: { iconUrl?: string } | null, | |
| 343 | 341 | ): McpSourceConfigPayload => ({ |
| 344 | 342 | name: source.name, |
| 345 | − ...(configSource?.iconUrl ? { iconUrl: configSource.iconUrl } : {}), | |
| 346 | 343 | endpoint: stored.endpoint, |
| 347 | 344 | transport: stored.transport, |
| 348 | 345 | queryParams: stored.queryParams, |
| @@ -692,9 +689,7 @@ export const mcpSdkPlugin = ( · 343 unmodified lines | ||
| 692 | 689 | endpoint: input.endpoint, |
| 693 | 690 | command: input.command, |
| 694 | 691 | }), |
| 695 | − ...(input.iconUrl && input.iconUrl.trim().length > 0 | |
| 696 | − ? { iconUrl: input.iconUrl.trim() } | |
| 697 | − : {}), | |
| 692 | + ...(input.iconUrl?.trim() ? { iconUrl: input.iconUrl.trim() } : {}), | |
| 698 | 693 | }, |
| 699 | 694 | stored: Effect.runSync(normalizeStoredSourceData(input)), |
| 700 | 695 | }), |
| @@ -710,15 +705,13 @@ export const mcpSdkPlugin = ( · 9 unmodified lines | ||
| 710 | 705 | endpoint: stored.endpoint, |
| 711 | 706 | command: stored.command, |
| 712 | 707 | }), |
| 713 | − ...(config.iconUrl && config.iconUrl.trim().length > 0 | |
| 714 | − ? { iconUrl: config.iconUrl.trim() } | |
| 715 | − : { iconUrl: undefined }), | |
| 708 | + ...(config.iconUrl?.trim() ? { iconUrl: config.iconUrl.trim() } : {}), | |
| 716 | 709 | }, |
| 717 | 710 | stored, |
| 718 | 711 | }; |
| 719 | 712 | }, |
| 720 | − toConfig: ({ source, stored, configSource }) => | |
| 721 | − sourceConfigFromStored(source, stored, configSource), | |
| 713 | + toConfig: ({ source, stored }) => | |
| 714 | + sourceConfigFromStored(source, stored), | |
| 722 | 715 | remove: ({ stored }) => |
| 723 | 716 | Effect.gen(function* () { |
| 724 | 717 | if (stored?.auth.kind === "oauth2") { |
| @@ -731,11 +724,10 @@ export const mcpSdkPlugin = ( · 6 unmodified lines | ||
| 731 | 724 | }), |
| 732 | 725 | }, |
| 733 | 726 | scopeConfig: { |
| 734 | − toConfigSource: ({ source, stored, configInput }) => | |
| 727 | + toConfigSource: ({ source, stored }) => | |
| 735 | 728 | pluginScopeConfigSourceFromConfig({ |
| 736 | 729 | source, |
| 737 | 730 | config: stored, |
| 738 | − iconUrl: configuredIconUrlFromConfigInput(configInput), | |
| 739 | 731 | }), |
| 740 | 732 | recoverStored: ({ config }) => |
| 741 | 733 | mcpStoredSourceDataFromLocalConfig(config), |
| @@ -16,6 +16,7 @@ import { · 15 unmodified lines | ||
| 16 | 16 | |
| 17 | 17 | export { getFaviconUrlForRemoteUrl } from "@executor/source-core"; |
| 18 | 18 | |
| 19 | + | |
| 19 | 20 | export const McpConnectionAuthSchema = Schema.Union( |
| 20 | 21 | Schema.Struct({ |
| 21 | 22 | kind: Schema.Literal("none"), |
| @@ -18,7 +18,6 @@ import { · 17 unmodified lines | ||
| 18 | 18 | defineExecutorSourcePlugin, |
| 19 | 19 | } from "@executor/platform-sdk/plugins"; |
| 20 | 20 | import { |
| 21 | − configuredIconUrlFromConfigInput, | |
| 22 | 21 | createPluginScopeConfigEntrySchema, |
| 23 | 22 | pluginScopeConfigSourceFromConfig, |
| 24 | 23 | SecretMaterialResolverService, |
| @@ -186,10 +185,8 @@ const createStoredSourceData = ( · 161 unmodified lines | ||
| 186 | 185 | const configFromStoredSourceData = ( |
| 187 | 186 | source: Source, |
| 188 | 187 | stored: OpenApiStoredSourceData, |
| 189 | − configSource: { iconUrl?: string } | null, | |
| 190 | 188 | ): OpenApiSourceConfigPayload => ({ |
| 191 | 189 | name: source.name, |
| 192 | − ...(configSource?.iconUrl ? { iconUrl: configSource.iconUrl } : {}), | |
| 193 | 190 | specUrl: stored.specUrl, |
| 194 | 191 | baseUrl: stored.baseUrl, |
| 195 | 192 | auth: stored.auth, |
| @@ -527,6 +524,7 @@ export const openApiSdkPlugin = ( · 331 unmodified lines | ||
| 527 | 524 | specUrl: input.specUrl, |
| 528 | 525 | title: input.name, |
| 529 | 526 | }), |
| 527 | + ...(input.iconUrl?.trim() ? { iconUrl: input.iconUrl.trim() } : {}), | |
| 530 | 528 | }, |
| 531 | 529 | stored: createStoredSourceData(input), |
| 532 | 530 | }), |
| @@ -538,14 +536,15 @@ export const openApiSdkPlugin = ( · 5 unmodified lines | ||
| 538 | 536 | specUrl: config.specUrl, |
| 539 | 537 | title: config.name, |
| 540 | 538 | }), |
| 539 | + ...(config.iconUrl?.trim() ? { iconUrl: config.iconUrl.trim() } : {}), | |
| 541 | 540 | }, |
| 542 | 541 | stored: createStoredSourceData(config), |
| 543 | 542 | }), |
| 544 | − toConfig: ({ source, stored, configSource }) => | |
| 545 | − configFromStoredSourceData(source, normalizeStoredSourceData(stored), configSource), | |
| 543 | + toConfig: ({ source, stored }) => | |
| 544 | + configFromStoredSourceData(source, normalizeStoredSourceData(stored)), | |
| 546 | 545 | }, |
| 547 | 546 | scopeConfig: { |
| 548 | − toConfigSource: ({ source, stored, configInput }) => | |
| 547 | + toConfigSource: ({ source, stored }) => | |
| 549 | 548 | pluginScopeConfigSourceFromConfig({ |
| 550 | 549 | source, |
| 551 | 550 | config: { |
| @@ -554,7 +553,6 @@ export const openApiSdkPlugin = ( · 2 unmodified lines | ||
| 554 | 553 | auth: stored.auth, |
| 555 | 554 | defaultHeaders: stored.defaultHeaders, |
| 556 | 555 | }, |
| 557 | − iconUrl: configuredIconUrlFromConfigInput(configInput), | |
| 558 | 556 | }), |
| 559 | 557 | recoverStored: ({ config, loadedConfig }) => |
| 560 | 558 | openApiStoredSourceDataFromLocalConfig({ |