Showing the changes to packages/plugins/openapi/src (3 of 17 files). Show all
Unified · Split
| @@ -1,6 +1,6 @@ | |||
| 1 | import { HttpApiEndpoint, HttpApiGroup, HttpApiSchema } from "@effect/platform"; | 1 | import { HttpApiEndpoint, HttpApiGroup, HttpApiSchema } from "@effect/platform"; |
| 2 | import { Schema } from "effect"; | 2 | import { Schema } from "effect"; |
| 3 | import { ScopeId } from "@executor/sdk"; | 3 | import { ScopeId, SecretBackedValue } from "@executor/sdk"; |
| 4 | import { InternalError } from "@executor/api"; | 4 | import { InternalError } from "@executor/api"; |
| 5 | 5 | ||
| 6 | import { OpenApiParseError, OpenApiExtractionError, OpenApiOAuthError } from "../sdk/errors"; | 6 | import { OpenApiParseError, OpenApiExtractionError, OpenApiOAuthError } from "../sdk/errors"; |
| @@ -21,14 +21,6 @@ const scopeIdParam = HttpApiSchema.param("scopeId", ScopeId); · 14 unmodified lines | |||
| 21 | const namespaceParam = HttpApiSchema.param("namespace", Schema.String); | 21 | const namespaceParam = HttpApiSchema.param("namespace", Schema.String); |
| 22 | const sourceScopeIdParam = HttpApiSchema.param("sourceScopeId", ScopeId); | 22 | const sourceScopeIdParam = HttpApiSchema.param("sourceScopeId", ScopeId); |
| 23 | 23 | ||
| 24 | const SecretBackedValue = Schema.Union( | ||
| 25 | Schema.String, | ||
| 26 | Schema.Struct({ | ||
| 27 | secretId: Schema.String, | ||
| 28 | prefix: Schema.optional(Schema.String), | ||
| 29 | }), | ||
| 30 | ); | ||
| 31 | |||
| 32 | const SpecFetchCredentialsPayload = Schema.Struct({ | 24 | const SpecFetchCredentialsPayload = Schema.Struct({ |
| 33 | headers: Schema.optional(Schema.Record({ key: Schema.String, value: SecretBackedValue })), | 25 | headers: Schema.optional(Schema.Record({ key: Schema.String, value: SecretBackedValue })), |
| 34 | queryParams: Schema.optional(Schema.Record({ key: Schema.String, value: SecretBackedValue })), | 26 | queryParams: Schema.optional(Schema.Record({ key: Schema.String, value: SecretBackedValue })), |
| @@ -8,6 +8,7 @@ import { · 7 unmodified lines | |||
| 8 | SecretId, | 8 | SecretId, |
| 9 | SourceDetectionResult, | 9 | SourceDetectionResult, |
| 10 | definePlugin, | 10 | definePlugin, |
| 11 | resolveSecretBackedMap, | ||
| 11 | type PluginCtx, | 12 | type PluginCtx, |
| 12 | type StorageFailure, | 13 | type StorageFailure, |
| 13 | type ToolAnnotations, | 14 | type ToolAnnotations, |
| @@ -471,39 +472,31 @@ const resolveConfiguredHeaders = ( · 457 unmodified lines | |||
| 471 | return resolved; | 472 | return resolved; |
| 472 | }); | 473 | }); |
| 473 | 474 | ||
| 474 | const resolveHeaderValue = ( | 475 | const resolveHeaderValues = ( |
| 475 | ctx: PluginCtx<OpenapiStore>, | 476 | ctx: PluginCtx<OpenapiStore>, |
| 476 | name: string, | 477 | values: Record<string, HeaderValue> | undefined, |
| 477 | value: HeaderValue, | 478 | ): Effect.Effect<Record<string, string>, OpenApiOAuthError | StorageFailure> => |
| 478 | ): Effect.Effect<string, OpenApiOAuthError | StorageFailure> => { | 479 | resolveSecretBackedMap({ |
| 479 | if (typeof value === "string") return Effect.succeed(value); | 480 | values, |
| 480 | return ctx.secrets.get(value.secretId).pipe( | 481 | getSecret: ctx.secrets.get, |
| 481 | Effect.mapError((err) => | 482 | onMissing: (name) => |
| 483 | new OpenApiOAuthError({ | ||
| 484 | message: `Secret not found for "${name}"`, | ||
| 485 | }), | ||
| 486 | onError: (err, name) => | ||
| 482 | "_tag" in err && err._tag === "SecretOwnedByConnectionError" | 487 | "_tag" in err && err._tag === "SecretOwnedByConnectionError" |
| 483 | ? new OpenApiOAuthError({ | 488 | ? new OpenApiOAuthError({ |
| 484 | message: `Secret not found for "${name}"`, | 489 | message: `Secret not found for "${name}"`, |
| 485 | }) | 490 | }) |
| 486 | : err, | 491 | : err, |
| 492 | }).pipe( | ||
| 493 | Effect.mapError((err) => | ||
| 494 | "_tag" in err && err._tag === "SecretOwnedByConnectionError" | ||
| 495 | ? new OpenApiOAuthError({ message: "Secret resolution failed" }) | ||
| 496 | : err, | ||
| 487 | ), | 497 | ), |
| 488 | Effect.flatMap((secret) => | 498 | Effect.map((resolved) => resolved ?? {}), |
| 489 | secret === null | ||
| 490 | ? Effect.fail( | ||
| 491 | new OpenApiOAuthError({ | ||
| 492 | message: `Secret not found for "${name}"`, | ||
| 493 | }), | ||
| 494 | ) | ||
| 495 | : Effect.succeed(value.prefix ? `${value.prefix}${secret}` : secret), | ||
| 496 | ), | ||
| 497 | ); | 499 | ); |
| 498 | }; | ||
| 499 | |||
| 500 | const resolveHeaderValues = ( | ||
| 501 | ctx: PluginCtx<OpenapiStore>, | ||
| 502 | values: Record<string, HeaderValue> | undefined, | ||
| 503 | ): Effect.Effect<Record<string, string>, OpenApiOAuthError | StorageFailure> => | ||
| 504 | Effect.forEach(Object.entries(values ?? {}), ([name, value]) => | ||
| 505 | Effect.map(resolveHeaderValue(ctx, name, value), (resolved) => [name, resolved] as const), | ||
| 506 | ).pipe(Effect.map((entries) => Object.fromEntries(entries))); | ||
| 507 | 500 | ||
| 508 | const resolveOAuthConnectionId = ( | 501 | const resolveOAuthConnectionId = ( |
| 509 | ctx: PluginCtx<OpenapiStore>, | 502 | ctx: PluginCtx<OpenapiStore>, |
| @@ -1,5 +1,5 @@ | |||
| 1 | import { Schema } from "effect"; | 1 | import { Schema } from "effect"; |
| 2 | import { ConnectionId, ScopeId, SecretId } from "@executor/sdk"; | 2 | import { ConnectionId, ScopeId, SecretBackedValue, SecretId } from "@executor/sdk"; |
| 3 | 3 | ||
| 4 | // --------------------------------------------------------------------------- | 4 | // --------------------------------------------------------------------------- |
| 5 | // Branded IDs | 5 | // Branded IDs |
| @@ -61,10 +61,9 @@ export class EncodingObject extends Schema.Class<EncodingObject>("EncodingObject · 55 unmodified lines | |||
| 61 | export class MediaBinding extends Schema.Class<MediaBinding>("MediaBinding")({ | 61 | export class MediaBinding extends Schema.Class<MediaBinding>("MediaBinding")({ |
| 62 | contentType: Schema.String, | 62 | contentType: Schema.String, |
| 63 | schema: Schema.optionalWith(Schema.Unknown, { as: "Option" }), | 63 | schema: Schema.optionalWith(Schema.Unknown, { as: "Option" }), |
| 64 | encoding: Schema.optionalWith( | 64 | encoding: Schema.optionalWith(Schema.Record({ key: Schema.String, value: EncodingObject }), { |
| 65 | Schema.Record({ key: Schema.String, value: EncodingObject }), | 65 | as: "Option", |
| 66 | { as: "Option" }, | 66 | }), |
| 67 | ), | ||
| 68 | }) {} | 67 | }) {} |
| 69 | 68 | ||
| 70 | export class OperationRequestBody extends Schema.Class<OperationRequestBody>( | 69 | export class OperationRequestBody extends Schema.Class<OperationRequestBody>( |
| @@ -137,13 +136,7 @@ export class OperationBinding extends Schema.Class<OperationBinding>("OperationB · 66 unmodified lines | |||
| 137 | * A header value — either a static string or a reference to a secret. | 136 | * A header value — either a static string or a reference to a secret. |
| 138 | * Stored as JSON-serializable data. | 137 | * Stored as JSON-serializable data. |
| 139 | */ | 138 | */ |
| 140 | export const HeaderValue = Schema.Union( | 139 | export const HeaderValue = SecretBackedValue; |
| 141 | Schema.String, | ||
| 142 | Schema.Struct({ | ||
| 143 | secretId: Schema.String, | ||
| 144 | prefix: Schema.optional(Schema.String), | ||
| 145 | }), | ||
| 146 | ); | ||
| 147 | export type HeaderValue = typeof HeaderValue.Type; | 140 | export type HeaderValue = typeof HeaderValue.Type; |
| 148 | 141 | ||
| 149 | export class ConfiguredHeaderBinding extends Schema.Class<ConfiguredHeaderBinding>( | 142 | export class ConfiguredHeaderBinding extends Schema.Class<ConfiguredHeaderBinding>( |
| @@ -154,10 +147,7 @@ export class ConfiguredHeaderBinding extends Schema.Class<ConfiguredHeaderBindin · 4 unmodified lines | |||
| 154 | prefix: Schema.optional(Schema.String), | 147 | prefix: Schema.optional(Schema.String), |
| 155 | }) {} | 148 | }) {} |
| 156 | 149 | ||
| 157 | export const ConfiguredHeaderValue = Schema.Union( | 150 | export const ConfiguredHeaderValue = Schema.Union(Schema.String, ConfiguredHeaderBinding); |
| 158 | Schema.String, | ||
| 159 | ConfiguredHeaderBinding, | ||
| 160 | ); | ||
| 161 | export type ConfiguredHeaderValue = typeof ConfiguredHeaderValue.Type; | 151 | export type ConfiguredHeaderValue = typeof ConfiguredHeaderValue.Type; |
| 162 | 152 | ||
| 163 | export const OpenApiSourceBindingValue = Schema.Union( | 153 | export const OpenApiSourceBindingValue = Schema.Union( |