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