(input: {
readonly integration: IntegrationRecord;
readonly credential: {
readonly template: AuthTemplateSlug;
readonly values: Record<string, string | null>;
};
readonly spec?: { readonly operation: string };
readonly httpClientLayer: Layer.Layer<HttpClient.HttpClient>;
})
| 677 | }; |
| 678 | |
| 679 | const checkGraphqlHealth = (input: { |
| 680 | readonly integration: IntegrationRecord; |
| 681 | readonly credential: { |
| 682 | readonly template: AuthTemplateSlug; |
| 683 | readonly values: Record<string, string | null>; |
| 684 | }; |
| 685 | readonly spec?: { readonly operation: string }; |
| 686 | readonly httpClientLayer: Layer.Layer<HttpClient.HttpClient>; |
| 687 | }): Effect.Effect<HealthCheckResult, never> => |
| 688 | Effect.gen(function* () { |
| 689 | const checkedAt = Date.now(); |
| 690 | const decoded = yield* decodeGraphqlIntegrationConfig(input.integration.config).pipe( |
| 691 | Effect.option, |
| 692 | ); |
| 693 | if (Option.isNone(decoded)) { |
| 694 | return { |
| 695 | status: "unknown", |
| 696 | checkedAt, |
| 697 | detail: "The GraphQL integration configuration is invalid. Edit it, then try again.", |
| 698 | } satisfies HealthCheckResult; |
| 699 | } |
| 700 | |
| 701 | const config = decoded.value; |
| 702 | const operation = |
| 703 | input.spec?.operation ?? |
| 704 | (config.introspectionHash === undefined ? GRAPHQL_HEALTH_OPERATION : undefined); |
| 705 | if (operation === undefined) { |
| 706 | return { |
| 707 | status: "unknown", |
| 708 | checkedAt, |
| 709 | detail: "No live schema health check is configured.", |
| 710 | } satisfies HealthCheckResult; |
| 711 | } |
| 712 | if (operation !== GRAPHQL_HEALTH_OPERATION) { |
| 713 | return { |
| 714 | status: "unknown", |
| 715 | checkedAt, |
| 716 | detail: `GraphQL health check operation "${operation}" is not supported. Use ${GRAPHQL_HEALTH_OPERATION}.`, |
| 717 | } satisfies HealthCheckResult; |
| 718 | } |
| 719 | |
| 720 | const method = config.authenticationTemplate.find( |
| 721 | (candidate: GraphqlAuthMethod) => candidate.slug === String(input.credential.template), |
| 722 | ); |
| 723 | const missing = missingCredentialVariables(method, input.credential.values); |
| 724 | if (missing.length > 0) { |
| 725 | return { |
| 726 | status: "expired", |
| 727 | checkedAt, |
| 728 | detail: `Enter a credential value for ${missing.join(", ")}, then try again.`, |
| 729 | reason: "credential_missing", |
| 730 | } satisfies HealthCheckResult; |
| 731 | } |
| 732 | |
| 733 | const auth = introspectHeadersForConnection( |
| 734 | config, |
| 735 | input.credential.values, |
| 736 | input.credential.template, |
no test coverage detected