(input: {
readonly ctx: PluginCtx<OpenapiStore>;
readonly integration: IntegrationRecord;
readonly credential: ToolInvocationCredential;
readonly spec?: HealthCheckSpec;
readonly httpClientLayer: Layer.Layer<HttpClient.HttpClient, never, never>;
})
| 872 | * reasons: a rejected credential is a `HealthCheckResult` with |
| 873 | * `status: "expired"`, not an error. */ |
| 874 | export const checkHealthOpenApi = (input: { |
| 875 | readonly ctx: PluginCtx<OpenapiStore>; |
| 876 | readonly integration: IntegrationRecord; |
| 877 | readonly credential: ToolInvocationCredential; |
| 878 | readonly spec?: HealthCheckSpec; |
| 879 | readonly httpClientLayer: Layer.Layer<HttpClient.HttpClient, never, never>; |
| 880 | }): Effect.Effect<HealthCheckResult, StorageFailure> => |
| 881 | Effect.gen(function* () { |
| 882 | const checkedAt = Date.now(); |
| 883 | const config = decodeOpenApiIntegrationConfig(input.integration.config); |
| 884 | const spec = input.spec; |
| 885 | if (!spec) { |
| 886 | return { |
| 887 | status: "unknown", |
| 888 | checkedAt, |
| 889 | detail: "No health check configured.", |
| 890 | } satisfies HealthCheckResult; |
| 891 | } |
| 892 | |
| 893 | const integration = String(input.integration.slug); |
| 894 | const binding = yield* resolveHealthCheckBinding( |
| 895 | input.ctx, |
| 896 | integration, |
| 897 | spec.operation, |
| 898 | config, |
| 899 | ); |
| 900 | if (!binding) { |
| 901 | return { |
| 902 | status: "unknown", |
| 903 | checkedAt, |
| 904 | detail: `Health check operation "${spec.operation}" not found on "${integration}".`, |
| 905 | } satisfies HealthCheckResult; |
| 906 | } |
| 907 | |
| 908 | // HARD block, not just a ranking hint: a health check runs unattended and |
| 909 | // repeatedly, so a mutating operation must never execute through it. The |
| 910 | // normal tool path gates these behind approval, and this path has no |
| 911 | // approval step. The candidate list labels these "(writes)"; refusing here |
| 912 | // is the enforcement. |
| 913 | if (REQUIRE_APPROVAL.has(binding.method.toLowerCase())) { |
| 914 | return { |
| 915 | status: "unknown", |
| 916 | checkedAt, |
| 917 | detail: `Health check operation "${spec.operation}" is a ${binding.method.toUpperCase()} (mutating): pick a read-only operation.`, |
| 918 | } satisfies HealthCheckResult; |
| 919 | } |
| 920 | |
| 921 | const headers: Record<string, string> = { ...(config?.headers ?? {}) }; |
| 922 | const queryParams: Record<string, string> = { ...(config?.queryParams ?? {}) }; |
| 923 | |
| 924 | const template = (config?.authenticationTemplate ?? []).find( |
| 925 | (entry) => String(entry.slug) === String(input.credential.template), |
| 926 | ); |
| 927 | if (template) { |
| 928 | const missing = requiredTemplateVariables(template).filter((name) => { |
| 929 | const value = input.credential.values[name]; |
| 930 | return value == null || value === ""; |
| 931 | }); |
no test coverage detected