| @@ -529,20 +529,29 @@ const targetScopeForBinding = ( · 528 unmodified lines |
| 529 | ); | 529 | ); |
| 530 | }; | 530 | }; |
| 531 | | 531 | |
| 532 | const resolveEffectiveSourceConfig = ( | 532 | const findOuterSource = ( |
| 533 | ctx: PluginCtx<OpenapiStore>, | 533 | ctx: PluginCtx<OpenapiStore>, |
| 534 | base: StoredSource, | 534 | namespace: string, |
| 535 | ): Effect.Effect<EffectiveSourceConfig, StorageFailure> => | 535 | scope: string, |
| | 536 | ): Effect.Effect<StoredSource | null, StorageFailure> => |
| 536 | Effect.gen(function* () { | 537 | Effect.gen(function* () { |
| 537 | const ranks = scopeRanks(ctx); | 538 | const ranks = scopeRanks(ctx); |
| 538 | const baseRank = scopeRank(ranks, base.scope); | 539 | const baseRank = scopeRank(ranks, scope); |
| 539 | let fallback: StoredSource | null = null; | | |
| 540 | for (let index = baseRank + 1; index < ctx.scopes.length; index++) { | 540 | for (let index = baseRank + 1; index < ctx.scopes.length; index++) { |
| 541 | const scope = ctx.scopes[index]; | 541 | const candidateScope = ctx.scopes[index]; |
| 542 | if (!scope) continue; | 542 | if (!candidateScope) continue; |
| 543 | fallback = yield* ctx.storage.getSource(base.namespace, scope.id); | 543 | const source = yield* ctx.storage.getSource(namespace, candidateScope.id); |
| 544 | if (fallback) break; | 544 | if (source) return source; |
| 545 | } | 545 | } |
| | 546 | return null; |
| | 547 | }); |
| | 548 | |
| | 549 | const resolveEffectiveSourceConfig = ( |
| | 550 | ctx: PluginCtx<OpenapiStore>, |
| | 551 | base: StoredSource, |
| | 552 | ): Effect.Effect<EffectiveSourceConfig, StorageFailure> => |
| | 553 | Effect.gen(function* () { |
| | 554 | const fallback = yield* findOuterSource(ctx, base.namespace, base.scope); |
| 546 | | 555 | |
| 547 | if (!fallback) { | 556 | if (!fallback) { |
| 548 | return { | 557 | return { |
| @@ -561,7 +570,7 @@ const resolveEffectiveSourceConfig = ( · 12 unmodified lines |
| 561 | config: { | 570 | config: { |
| 562 | ...base.config, | 571 | ...base.config, |
| 563 | sourceUrl: base.config.sourceUrl ?? fallback.config.sourceUrl, | 572 | sourceUrl: base.config.sourceUrl ?? fallback.config.sourceUrl, |
| 564 | baseUrl: base.config.baseUrl || fallback.config.baseUrl, | 573 | baseUrl: fallback.config.baseUrl, |
| 565 | namespace: base.config.namespace ?? fallback.config.namespace, | 574 | namespace: base.config.namespace ?? fallback.config.namespace, |
| 566 | headers: hasBaseHeaders ? base.config.headers : fallback.config.headers, | 575 | headers: hasBaseHeaders ? base.config.headers : fallback.config.headers, |
| 567 | queryParams: hasBaseQueryParams ? base.config.queryParams : fallback.config.queryParams, | 576 | queryParams: hasBaseQueryParams ? base.config.queryParams : fallback.config.queryParams, |
| @@ -806,6 +815,12 @@ export const openApiPlugin = definePlugin((options?: OpenApiPluginOptions) => { · 238 unmodified lines |
| 806 | Option.getOrElse(result.title, () => "api") | 815 | Option.getOrElse(result.title, () => "api") |
| 807 | .toLowerCase() | 816 | .toLowerCase() |
| 808 | .replace(/[^a-z0-9]+/g, "_"); | 817 | .replace(/[^a-z0-9]+/g, "_"); |
| | 818 | const outerSource = yield* findOuterSource(ctx, namespace, input.scope); |
| | 819 | if (outerSource && input.baseUrl !== undefined && input.baseUrl.trim() !== "") { |
| | 820 | return yield* new OpenApiOAuthError({ |
| | 821 | message: "OpenAPI source shadows inherit the outer source base URL", |
| | 822 | }); |
| | 823 | } |
| 809 | | 824 | |
| 810 | const hoistedDefs: Record<string, unknown> = {}; | 825 | const hoistedDefs: Record<string, unknown> = {}; |
| 811 | if (doc.components?.schemas) { | 826 | if (doc.components?.schemas) { |
| @@ -814,7 +829,7 @@ export const openApiPlugin = definePlugin((options?: OpenApiPluginOptions) => { · 2 unmodified lines |
| 814 | } | 829 | } |
| 815 | } | 830 | } |
| 816 | | 831 | |
| 817 | const baseUrl = input.baseUrl ?? resolveBaseUrl(result.servers); | 832 | const baseUrl = outerSource ? undefined : (input.baseUrl ?? resolveBaseUrl(result.servers)); |
| 818 | const canonicalHeaders = canonicalizeHeaders(input.headers); | 833 | const canonicalHeaders = canonicalizeHeaders(input.headers); |
| 819 | const canonicalQueryParams = canonicalizeCredentialMap( | 834 | const canonicalQueryParams = canonicalizeCredentialMap( |
| 820 | input.queryParams, | 835 | input.queryParams, |
| @@ -1073,6 +1088,14 @@ export const openApiPlugin = definePlugin((options?: OpenApiPluginOptions) => { · 252 unmodified lines |
| 1073 | ...(input.oauth2 !== undefined ? ["oauth2:"] : []), | 1088 | ...(input.oauth2 !== undefined ? ["oauth2:"] : []), |
| 1074 | ]; | 1089 | ]; |
| 1075 | const targetScope = input.credentialTargetScope ?? scope; | 1090 | const targetScope = input.credentialTargetScope ?? scope; |
| | 1091 | if (input.baseUrl !== undefined && input.baseUrl.trim() !== "") { |
| | 1092 | const outerSource = yield* findOuterSource(ctx, namespace, scope); |
| | 1093 | if (outerSource) { |
| | 1094 | return yield* new OpenApiOAuthError({ |
| | 1095 | message: "OpenAPI source shadows inherit the outer source base URL", |
| | 1096 | }); |
| | 1097 | } |
| | 1098 | } |
| 1076 | if (affectedPrefixes.length > 0 || directBindings.length > 0) { | 1099 | if (affectedPrefixes.length > 0 || directBindings.length > 0) { |
| 1077 | yield* validateOpenApiBindingTarget(ctx, { | 1100 | yield* validateOpenApiBindingTarget(ctx, { |
| 1078 | sourceId: namespace, | 1101 | sourceId: namespace, |