module Web.Controller.Api.V2.OpenApi where -- GET /api/v2/openapi.json — OpenAPI 3.1 spec with live type registry enums -- GET /api/v2/openapi.yaml — YAML convenience alias -- GET /api/v2/docs — Swagger UI import Web.Types import Generated.Types import IHP.Prelude import IHP.ControllerPrelude import Data.Aeson (object, (.=), Array, toJSON) import qualified Data.Aeson as A import qualified Data.Aeson.Key as K import qualified Data.Vector as V import qualified Data.Text as T import qualified Data.Text.Encoding as TE import qualified Data.Yaml as Yaml -- yaml package import qualified Data.ByteString.Lazy as LBS import Application.Helper.TypeRegistry ( activeWidgetTypes, activeEventTypes, activeAnnotationCategories , activePolicyScopes ) import Network.HTTP.Types (status200) import Network.Wai (responseLBS) instance Controller ApiV2OpenApiController where action ApiV2OpenApiJsonAction = do spec <- buildOpenApiSpec respondAndExit $ responseLBS status200 [("Content-Type", "application/json")] (A.encode spec) action ApiV2OpenApiYamlAction = do spec <- buildOpenApiSpec let yaml = Yaml.encode spec respondAndExit $ responseLBS status200 [("Content-Type", "application/yaml")] (LBS.fromStrict yaml) action ApiV2DocsAction = do respondAndExit $ responseLBS status200 [("Content-Type", "text/html; charset=utf-8")] swaggerUiHtml -- | Build the full OpenAPI 3.1 document from live registry data. buildOpenApiSpec :: (?modelContext :: ModelContext) => IO Value buildOpenApiSpec = do (fwWidgetTypes, ownedWidgetTypes) <- activeWidgetTypes let allWidgetTypes = fwWidgetTypes ++ ownedWidgetTypes eventTypes <- activeEventTypes annCats <- activeAnnotationCategories policyScopes <- activePolicyScopes let wtEnum = toJSON $ map (.name) allWidgetTypes let etEnum = toJSON $ map (.name) eventTypes let acEnum = toJSON $ map (.name) annCats let psEnum = toJSON $ map (.name) policyScopes pure $ object [ "openapi" .= ("3.1.0" :: Text) , "info" .= object [ "title" .= ("Interaction Hub Framework API" :: Text) , "version" .= ("2.0" :: Text) , "description" .= ("IHF external API v2. For the human-readable contract see /contracts/functional/interaction-reporting-v1.md" :: Text) ] , "x-ihf-contract" .= ("/contracts/functional/interaction-reporting-v1.md" :: Text) , "servers" .= [object ["url" .= ("/api/v2" :: Text)]] , "paths" .= buildPaths , "components" .= object [ "schemas" .= object [ "WidgetType" .= object [ "type" .= ("string" :: Text) , "enum" .= wtEnum ] , "EventType" .= object [ "type" .= ("string" :: Text) , "enum" .= etEnum ] , "AnnotationCategory" .= object [ "type" .= ("string" :: Text) , "enum" .= acEnum ] , "PolicyScope" .= object [ "type" .= ("string" :: Text) , "enum" .= psEnum ] , "PaginationMeta" .= object [ "type" .= ("object" :: Text) , "properties" .= object [ "page" .= object ["type" .= ("integer" :: Text)] , "per_page" .= object ["type" .= ("integer" :: Text)] , "total" .= object ["type" .= ("integer" :: Text)] ] ] , "Hub" .= hubSchema , "CreateHubRequest" .= createHubRequestSchema , "HubCapabilityManifest" .= manifestSchema , "CreateHubCapabilityManifestRequest" .= createManifestRequestSchema , "UpdateHubCapabilityManifestRequest" .= updateManifestRequestSchema , "ApiConsumer" .= apiConsumerSchema , "CreateApiConsumerRequest" .= createApiConsumerRequestSchema , "ApiKey" .= apiKeySchema , "CreateApiKeyRequest" .= createApiKeyRequestSchema , "ApiKeyCreatedResponse" .= apiKeyCreatedResponseSchema , "Widget" .= widgetSchema , "CreateWidgetRequest" .= createWidgetRequestSchema , "InteractionEvent" .= interactionEventSchema , "CreateInteractionEventRequest" .= createInteractionEventRequestSchema , "Annotation" .= annotationSchema , "CreateAnnotationRequest" .= createAnnotationRequestSchema , "RequirementCandidate" .= rcSchema , "DecisionRecord" .= drSchema , "DeploymentRecord" .= depSchema , "OutcomeSignal" .= sigSchema , "OutcomeCorrelation" .= outcomeCorrelationSchema , "PatternPerformanceRecord" .= patternPerformanceSchema , "InstitutionalKnowledgeEntry" .= institutionalKnowledgeSchema , "HubRegistryEntry" .= hubRegistryEntrySchema , "HubManifestSummary" .= hubManifestSummarySchema , "WidgetPattern" .= widgetPatternSchema , "WidgetPatternDetail" .= widgetPatternDetailSchema , "WidgetPatternVersion" .= widgetPatternVersionSchema , "PatternAdoptionResponse" .= patternAdoptionResponseSchema ] , "securitySchemes" .= object [ "BearerAuth" .= object [ "type" .= ("http" :: Text) , "scheme" .= ("bearer" :: Text) , "description" .= ("API key or OAuth token obtained via POST /api/v2/token" :: Text) ] ] ] , "security" .= [object ["BearerAuth" .= ([] :: [Text])]] ] buildPaths :: Value buildPaths = object [ "/hubs" .= object [ "get" .= listOp "Hub" [] , "post" .= writeOp "Hub" "CreateHubRequest" ] , "/hubs/{id}" .= getShowPath "Hub" , "/hub-capability-manifests" .= object [ "get" .= listOp "HubCapabilityManifest" [ ("hubId", "string", "uuid") , ("status", "string", "") ] , "post" .= writeOp "HubCapabilityManifest" "CreateHubCapabilityManifestRequest" ] , "/hub-capability-manifests/{id}" .= object [ "get" .= showOp "HubCapabilityManifest" , "patch" .= writeOpWithStatusAndParams "Update HubCapabilityManifest" "HubCapabilityManifest" "UpdateHubCapabilityManifestRequest" True "200" [pathParam "id"] ] , "/hub-capability-manifests/{id}/activate" .= object [ "post" .= postNoBodyOpWithStatusAndParams "Activate HubCapabilityManifest" "HubCapabilityManifest" "200" [pathParam "id"] ] , "/api-consumers" .= object [ "get" .= listOp "ApiConsumer" [] , "post" .= writeOp "ApiConsumer" "CreateApiConsumerRequest" ] , "/api-consumers/{id}" .= getShowPath "ApiConsumer" , "/api-consumers/{id}/api-keys" .= object [ "post" .= writeOpWithResponseStatusAndParams "Create ApiKey" "ApiKeyCreatedResponse" "CreateApiKeyRequest" False "201" [pathParam "id"] ] , "/widgets" .= object [ "get" .= listOp "Widget" [] , "post" .= writeOp "Widget" "CreateWidgetRequest" ] , "/widgets/{id}" .= getShowPath "Widget" , "/interaction-events" .= object [ "get" .= listOp "InteractionEvent" [ ("widgetId", "string", "uuid") , ("eventType", "string", "") ] , "post" .= writeOp "InteractionEvent" "CreateInteractionEventRequest" ] , "/annotations" .= object [ "get" .= listOp "Annotation" [ ("widgetId", "string", "uuid") , ("category", "string", "") ] , "post" .= writeOp "Annotation" "CreateAnnotationRequest" ] , "/requirement-candidates" .= getListPath "RequirementCandidate" , "/requirement-candidates/{id}" .= getShowPath "RequirementCandidate" , "/decision-records" .= getListPath "DecisionRecord" , "/decision-records/{id}" .= getShowPath "DecisionRecord" , "/deployment-records" .= getListPath "DeploymentRecord" , "/deployment-records/{id}" .= getShowPath "DeploymentRecord" , "/outcome-signals" .= getListPath "OutcomeSignal" , "/outcome-signals/{id}" .= getShowPath "OutcomeSignal" , "/widget-types" .= publicListPath "WidgetTypeRegistry" , "/event-types" .= publicListPath "EventTypeRegistry" , "/annotation-categories" .= publicListPath "AnnotationCategoryRegistry" , "/policy-scopes" .= publicListPath "PolicyScopeRegistry" , "/token" .= tokenPath -- Phase 10 — Hub Registry and Widget Marketplace , "/hub-registry" .= getListPath "HubRegistryEntry" , "/hub-registry/{hubId}" .= getShowPathWithParam "HubRegistryEntry" "hubId" , "/widget-patterns" .= getListPath "WidgetPattern" , "/widget-patterns/{id}" .= getShowPath "WidgetPatternDetail" , "/widget-patterns/{id}/adopt" .= object [ "post" .= postNoBodyOpWithStatusAndParams "Adopt WidgetPattern" "PatternAdoptionResponse" "200" [pathParam "id"] ] ] getListPath :: Text -> Value getListPath schemaName = object [ "get" .= listOp schemaName [] ] getShowPath :: Text -> Value getShowPath schemaName = object [ "get" .= showOp schemaName ] getShowPathWithParam :: Text -> Text -> Value getShowPathWithParam schemaName paramName = object [ "get" .= showOpWithParam schemaName paramName ] listOp :: Text -> [(Text, Text, Text)] -> Value listOp schemaName extraParams = object [ "summary" .= ("List " <> schemaName) , "security" .= [object ["BearerAuth" .= ([] :: [Text])]] , "parameters" .= (pageParams ++ map toParam extraParams) , "responses" .= object [ "200" .= object [ "description" .= ("OK" :: Text) , "content" .= object [ "application/json" .= object [ "schema" .= object [ "type" .= ("object" :: Text) , "properties" .= object [ "data" .= object [ "type" .= ("array" :: Text) , "items" .= object ["$ref" .= ("#/components/schemas/" <> schemaName)] ] , "meta" .= object ["$ref" .= ("#/components/schemas/PaginationMeta" :: Text)] ] ] ] ] ] , "401" .= object ["description" .= ("Unauthorized" :: Text)] ] ] where toParam (name, typ, fmt) = object $ [ "name" .= name, "in" .= ("query" :: Text) , "schema" .= object (["type" .= typ] ++ if fmt /= "" then [("format", A.String fmt)] else []) ] showOp :: Text -> Value showOp schemaName = showOpWithParam schemaName "id" showOpWithParam :: Text -> Text -> Value showOpWithParam schemaName paramName = object [ "summary" .= ("Get " <> schemaName) , "security" .= [object ["BearerAuth" .= ([] :: [Text])]] , "parameters" .= [pathParam paramName] , "responses" .= object [ "200" .= object [ "description" .= ("OK" :: Text) , "content" .= object [ "application/json" .= object ["schema" .= object ["$ref" .= ("#/components/schemas/" <> schemaName)]] ] ] , "401" .= object ["description" .= ("Unauthorized" :: Text)] , "404" .= object ["description" .= ("Not found" :: Text)] ] ] writeOp :: Text -> Text -> Value writeOp schemaName reqSchema = writeOpWithSummary ("Create " <> schemaName) schemaName reqSchema writeOpWithSummary :: Text -> Text -> Text -> Value writeOpWithSummary summaryText schemaName reqSchema = writeOpWithStatusAndParams summaryText schemaName reqSchema True "201" [] writeOpWithStatusAndParams :: Text -> Text -> Text -> Bool -> Text -> [Value] -> Value writeOpWithStatusAndParams = writeOpWithResponseStatusAndParams writeOpWithResponseStatusAndParams :: Text -> Text -> Text -> Bool -> Text -> [Value] -> Value writeOpWithResponseStatusAndParams summaryText responseSchema reqSchema bodyRequired successStatus params = object [ "summary" .= summaryText , "security" .= [object ["BearerAuth" .= ([] :: [Text])]] , "parameters" .= params , "requestBody" .= object [ "required" .= bodyRequired , "content" .= object [ "application/json" .= object ["schema" .= object ["$ref" .= ("#/components/schemas/" <> reqSchema)]] ] ] , "responses" .= object [ K.fromText successStatus .= object [ "description" .= ("OK" :: Text) , "content" .= object [ "application/json" .= object ["schema" .= object ["$ref" .= ("#/components/schemas/" <> responseSchema)]] ] ] , "400" .= object ["description" .= ("Invalid request" :: Text)] , "401" .= object ["description" .= ("Unauthorized" :: Text)] , "422" .= object ["description" .= ("Validation error" :: Text)] ] ] postNoBodyOpWithStatusAndParams :: Text -> Text -> Text -> [Value] -> Value postNoBodyOpWithStatusAndParams summaryText responseSchema successStatus params = object [ "summary" .= summaryText , "security" .= [object ["BearerAuth" .= ([] :: [Text])]] , "parameters" .= params , "responses" .= object [ K.fromText successStatus .= object [ "description" .= ("OK" :: Text) , "content" .= object [ "application/json" .= object ["schema" .= object ["$ref" .= ("#/components/schemas/" <> responseSchema)]] ] ] , "400" .= object ["description" .= ("Invalid request" :: Text)] , "401" .= object ["description" .= ("Unauthorized" :: Text)] , "422" .= object ["description" .= ("Validation error" :: Text)] ] ] pathParam :: Text -> Value pathParam name = object [ "name" .= name , "in" .= ("path" :: Text) , "required" .= True , "schema" .= uuidProp ] publicListPath :: Text -> Value publicListPath schemaName = object [ "get" .= object [ "summary" .= ("List registered " <> schemaName <> " values" :: Text) , "responses" .= object [ "200" .= object ["description" .= ("OK" :: Text)] ] ] ] tokenPath :: Value tokenPath = object [ "post" .= object [ "summary" .= ("Obtain OAuth access token (client credentials)" :: Text) , "requestBody" .= object [ "required" .= True , "content" .= object [ "application/x-www-form-urlencoded" .= object [ "schema" .= object [ "type" .= ("object" :: Text) , "properties" .= object [ "grant_type" .= object ["type" .= ("string" :: Text), "enum" .= ["client_credentials" :: Text]] , "client_id" .= object ["type" .= ("string" :: Text), "format" .= ("uuid" :: Text)] , "client_secret" .= object ["type" .= ("string" :: Text)] , "scope" .= object ["type" .= ("string" :: Text)] ] ] ] ] ] , "responses" .= object [ "200" .= object ["description" .= ("Access token issued" :: Text)] , "400" .= object ["description" .= ("Invalid request or credentials" :: Text)] ] ] ] pageParams :: [Value] pageParams = [ object ["name" .= ("page" :: Text), "in" .= ("query" :: Text), "schema" .= object ["type" .= ("integer" :: Text)]] , object ["name" .= ("per_page" :: Text), "in" .= ("query" :: Text), "schema" .= object ["type" .= ("integer" :: Text)]] ] -- Schemas for all resource types hubSchema :: Value hubSchema = object [ "type" .= ("object" :: Text) , "properties" .= object [ "id" .= uuidProp , "slug" .= strProp , "name" .= strProp , "domain" .= strProp , "hubKind" .= object ["type" .= ("string" :: Text), "enum" .= ["domain" :: Text, "shared"]] , "hubFamily" .= object ["type" .= ("string" :: Text), "enum" .= ["vsm" :: Text]] , "vsmFunction" .= strProp , "vsmSystem" .= object ["type" .= ("string" :: Text), "enum" .= ["1" :: Text, "2", "3", "3*", "4", "5", "environment"]] , "createdAt" .= object ["type" .= ("string" :: Text), "format" .= ("date-time" :: Text)] ] ] createHubRequestSchema :: Value createHubRequestSchema = object [ "type" .= ("object" :: Text) , "required" .= (["slug", "name", "domain"] :: [Text]) , "properties" .= object [ "slug" .= strProp , "name" .= strProp , "domain" .= strProp , "hubKind" .= object ["type" .= ("string" :: Text), "enum" .= ["domain" :: Text, "shared"]] , "hubFamily" .= object ["type" .= ("string" :: Text), "enum" .= ["vsm" :: Text]] , "vsmFunction" .= strProp , "vsmSystem" .= object ["type" .= ("string" :: Text), "enum" .= ["1" :: Text, "2", "3", "3*", "4", "5", "environment"]] ] ] widgetSchema :: Value widgetSchema = object [ "type" .= ("object" :: Text) , "properties" .= object [ "id" .= uuidProp , "hubId" .= uuidProp , "name" .= strProp , "widgetType" .= object ["$ref" .= ("#/components/schemas/WidgetType" :: Text)] , "capabilityRef" .= strProp , "viewContext" .= strProp , "policyScope" .= strProp , "status" .= strProp , "version" .= object ["type" .= ("integer" :: Text)] , "createdAt" .= object ["type" .= ("string" :: Text), "format" .= ("date-time" :: Text)] ] ] createWidgetRequestSchema :: Value createWidgetRequestSchema = object [ "type" .= ("object" :: Text) , "required" .= (["hubId", "name", "widgetType"] :: [Text]) , "properties" .= object [ "hubId" .= uuidProp , "name" .= strProp , "widgetType" .= object ["$ref" .= ("#/components/schemas/WidgetType" :: Text)] , "capabilityRef" .= strProp , "viewContext" .= strProp , "policyScope" .= object ["$ref" .= ("#/components/schemas/PolicyScope" :: Text)] , "status" .= object ["type" .= ("string" :: Text), "enum" .= ["active" :: Text, "deprecated", "draft"]] , "adapterSpecId" .= uuidProp ] ] manifestSchema :: Value manifestSchema = object [ "type" .= ("object" :: Text) , "properties" .= object [ "id" .= uuidProp , "hubId" .= uuidProp , "manifestVersion" .= strProp , "declaredWidgetTypes" .= object ["type" .= ("array" :: Text), "items" .= object ["$ref" .= ("#/components/schemas/WidgetType" :: Text)]] , "declaredEventTypes" .= object ["type" .= ("array" :: Text), "items" .= object ["$ref" .= ("#/components/schemas/EventType" :: Text)]] , "declaredAnnotationCategories" .= object ["type" .= ("array" :: Text), "items" .= object ["$ref" .= ("#/components/schemas/AnnotationCategory" :: Text)]] , "declaredPolicyScopes" .= object ["type" .= ("array" :: Text), "items" .= object ["$ref" .= ("#/components/schemas/PolicyScope" :: Text)]] , "capabilityDescription" .= strProp , "contact" .= strProp , "status" .= strProp , "activatedAt" .= dtProp , "createdAt" .= dtProp , "updatedAt" .= dtProp ] ] createManifestRequestSchema :: Value createManifestRequestSchema = object [ "type" .= ("object" :: Text) , "required" .= (["hubId"] :: [Text]) , "properties" .= manifestRequestProperties True ] updateManifestRequestSchema :: Value updateManifestRequestSchema = object [ "type" .= ("object" :: Text) , "properties" .= manifestRequestProperties False ] manifestRequestProperties :: Bool -> Value manifestRequestProperties includeHubId = object $ (if includeHubId then ["hubId" .= uuidProp] else []) ++ [ "manifestVersion" .= strProp , "declaredWidgetTypes" .= arrayOfRef "WidgetType" , "declaredEventTypes" .= arrayOfRef "EventType" , "declaredAnnotationCategories" .= arrayOfRef "AnnotationCategory" , "declaredPolicyScopes" .= arrayOfRef "PolicyScope" , "capabilityDescription" .= strProp , "contact" .= strProp ] apiConsumerSchema :: Value apiConsumerSchema = object [ "type" .= ("object" :: Text) , "properties" .= object [ "id" .= uuidProp , "name" .= strProp , "description" .= strProp , "hubCapabilityManifestId" .= uuidProp , "rateLimitPerMinute" .= object ["type" .= ("integer" :: Text)] , "quotaPerDay" .= object ["type" .= ("integer" :: Text)] , "quotaResetsAt" .= dtProp , "isActive" .= object ["type" .= ("boolean" :: Text)] , "createdAt" .= dtProp , "updatedAt" .= dtProp ] ] createApiConsumerRequestSchema :: Value createApiConsumerRequestSchema = object [ "type" .= ("object" :: Text) , "required" .= (["name"] :: [Text]) , "properties" .= object [ "name" .= strProp , "description" .= strProp , "hubCapabilityManifestId" .= uuidProp , "rateLimitPerMinute" .= object ["type" .= ("integer" :: Text), "minimum" .= (1 :: Int), "default" .= (60 :: Int)] , "quotaPerDay" .= object ["type" .= ("integer" :: Text), "minimum" .= (1 :: Int), "default" .= (10000 :: Int)] ] ] apiKeySchema :: Value apiKeySchema = object [ "type" .= ("object" :: Text) , "properties" .= object [ "id" .= uuidProp , "apiConsumerId" .= uuidProp , "keyPrefix" .= strProp , "scopes" .= strProp , "tokenType" .= strProp , "expiresAt" .= dtProp , "revokedAt" .= dtProp , "lastUsedAt" .= dtProp , "createdAt" .= dtProp ] ] createApiKeyRequestSchema :: Value createApiKeyRequestSchema = object [ "type" .= ("object" :: Text) , "properties" .= object [ "scopes" .= strProp ] ] apiKeyCreatedResponseSchema :: Value apiKeyCreatedResponseSchema = object [ "type" .= ("object" :: Text) , "properties" .= object [ "apiKey" .= object ["$ref" .= ("#/components/schemas/ApiKey" :: Text)] , "fullKey" .= object [ "type" .= ("string" :: Text) , "description" .= ("Static API key secret. Returned only in this creation response; it is stored hashed and cannot be recovered later." :: Text) ] , "displayOnce" .= boolProp ] ] interactionEventSchema :: Value interactionEventSchema = object [ "type" .= ("object" :: Text) , "properties" .= object [ "id" .= uuidProp , "widgetId" .= uuidProp , "eventType" .= object ["$ref" .= ("#/components/schemas/EventType" :: Text)] , "actorId" .= uuidProp , "actorType" .= strProp , "viewContextRef" .= strProp , "metadata" .= object ["type" .= ("object" :: Text)] , "occurredAt" .= dtProp ] ] createInteractionEventRequestSchema :: Value createInteractionEventRequestSchema = object [ "type" .= ("object" :: Text) , "required" .= (["widgetId", "eventType"] :: [Text]) , "properties" .= object [ "widgetId" .= uuidProp , "eventType" .= object ["$ref" .= ("#/components/schemas/EventType" :: Text)] , "viewContext" .= strProp , "metadata" .= objectProp ] ] annotationSchema :: Value annotationSchema = object [ "type" .= ("object" :: Text) , "properties" .= object [ "id" .= uuidProp , "widgetId" .= uuidProp , "parentId" .= uuidProp , "body" .= strProp , "category" .= object ["$ref" .= ("#/components/schemas/AnnotationCategory" :: Text)] , "severity" .= strProp , "threadId" .= uuidProp , "actorId" .= uuidProp , "actorType" .= strProp , "createdAt" .= dtProp ] ] createAnnotationRequestSchema :: Value createAnnotationRequestSchema = object [ "type" .= ("object" :: Text) , "required" .= (["widgetId", "category", "body"] :: [Text]) , "properties" .= object [ "widgetId" .= uuidProp , "category" .= object ["$ref" .= ("#/components/schemas/AnnotationCategory" :: Text)] , "body" .= strProp ] ] rcSchema :: Value rcSchema = object [ "type" .= ("object" :: Text) , "properties" .= object [ "id" .= uuidProp , "title" .= strProp , "description" .= strProp , "sourceWidgetId" .= uuidProp , "category" .= strProp , "status" .= strProp , "createdAt" .= dtProp ] ] drSchema :: Value drSchema = object [ "type" .= ("object" :: Text) , "properties" .= object [ "id" .= uuidProp , "title" .= strProp , "rationale" .= strProp , "outcome" .= strProp , "requirementId" .= uuidProp , "candidateId" .= uuidProp , "decidedAt" .= dtProp , "notes" .= strProp , "createdAt" .= dtProp ] ] depSchema :: Value depSchema = object [ "type" .= ("object" :: Text) , "properties" .= object [ "id" .= uuidProp , "decisionId" .= uuidProp , "versionRef" .= strProp , "deployedAt" .= dtProp , "notes" .= strProp , "createdAt" .= dtProp ] ] sigSchema :: Value sigSchema = object [ "type" .= ("object" :: Text) , "properties" .= object [ "id" .= uuidProp , "widgetId" .= uuidProp , "deploymentId" .= uuidProp , "signalType" .= strProp , "value" .= object ["type" .= ("number" :: Text)] , "observedAt" .= dtProp ] ] outcomeCorrelationSchema :: Value outcomeCorrelationSchema = object [ "type" .= ("object" :: Text) , "properties" .= object [ "id" .= uuidProp , "hubId" .= uuidProp , "annotationCategory" .= strProp , "correlationType" .= strProp , "correlationScore" .= object ["type" .= ("number" :: Text)] , "sampleCount" .= object ["type" .= ("integer" :: Text)] , "computedAt" .= dtProp ] ] patternPerformanceSchema :: Value patternPerformanceSchema = object [ "type" .= ("object" :: Text) , "properties" .= object [ "id" .= uuidProp , "widgetPatternId" .= uuidProp , "hubId" .= uuidProp , "adoptionCount" .= object ["type" .= ("integer" :: Text)] , "positiveOutcomeCount" .= object ["type" .= ("integer" :: Text)] , "totalOutcomeCount" .= object ["type" .= ("integer" :: Text)] , "positiveOutcomeRate" .= object ["type" .= ("number" :: Text)] , "meanOutcomeValue" .= object ["type" .= ("number" :: Text)] , "outcomeRank" .= object ["type" .= ("integer" :: Text)] , "calibratedAt" .= dtProp ] ] institutionalKnowledgeSchema :: Value institutionalKnowledgeSchema = object [ "type" .= ("object" :: Text) , "properties" .= object [ "id" .= uuidProp , "hubId" .= uuidProp , "decisionRecordId" .= uuidProp , "summary" .= strProp , "tags" .= object ["type" .= ("array" :: Text)] , "createdAt" .= dtProp , "updatedAt" .= dtProp ] ] hubRegistryEntrySchema :: Value hubRegistryEntrySchema = object [ "type" .= ("object" :: Text) , "properties" .= object [ "id" .= uuidProp , "name" .= strProp , "slug" .= strProp , "domain" .= strProp , "hubKind" .= strProp , "hubFamily" .= strProp , "vsmFunction" .= strProp , "vsmSystem" .= strProp , "gaafStatus" .= object ["type" .= ("string" :: Text), "enum" .= ["compliant" :: Text, "draft_only", "no_manifest"]] , "manifest" .= object ["$ref" .= ("#/components/schemas/HubManifestSummary" :: Text)] , "healthScore" .= intProp , "healthAt" .= dtProp ] ] hubManifestSummarySchema :: Value hubManifestSummarySchema = object [ "type" .= ("object" :: Text) , "properties" .= object [ "id" .= uuidProp , "manifestVersion" .= strProp , "status" .= strProp , "declaredWidgetTypes" .= arrayOfRef "WidgetType" , "declaredEventTypes" .= arrayOfRef "EventType" , "declaredAnnotationCategories" .= arrayOfRef "AnnotationCategory" , "declaredPolicyScopes" .= arrayOfRef "PolicyScope" , "activatedAt" .= dtProp ] ] widgetPatternSchema :: Value widgetPatternSchema = object [ "type" .= ("object" :: Text) , "properties" .= object [ "id" .= uuidProp , "hubId" .= uuidProp , "name" .= strProp , "description" .= strProp , "widgetType" .= object ["$ref" .= ("#/components/schemas/WidgetType" :: Text)] , "isCrossHub" .= boolProp , "isPublished" .= boolProp , "createdAt" .= dtProp , "updatedAt" .= dtProp ] ] widgetPatternDetailSchema :: Value widgetPatternDetailSchema = object [ "type" .= ("object" :: Text) , "properties" .= object [ "pattern" .= object ["$ref" .= ("#/components/schemas/WidgetPattern" :: Text)] , "versions" .= object [ "type" .= ("array" :: Text) , "items" .= object ["$ref" .= ("#/components/schemas/WidgetPatternVersion" :: Text)] ] , "adopterCount" .= intProp ] ] widgetPatternVersionSchema :: Value widgetPatternVersionSchema = object [ "type" .= ("object" :: Text) , "properties" .= object [ "id" .= uuidProp , "versionNumber" .= intProp , "definition" .= objectProp , "changelog" .= strProp , "publishedAt" .= dtProp ] ] patternAdoptionResponseSchema :: Value patternAdoptionResponseSchema = object [ "type" .= ("object" :: Text) , "properties" .= object [ "adopted" .= boolProp , "adoptionId" .= uuidProp ] ] uuidProp :: Value uuidProp = object ["type" .= ("string" :: Text), "format" .= ("uuid" :: Text)] strProp :: Value strProp = object ["type" .= ("string" :: Text)] intProp :: Value intProp = object ["type" .= ("integer" :: Text)] boolProp :: Value boolProp = object ["type" .= ("boolean" :: Text)] objectProp :: Value objectProp = object [ "type" .= ("object" :: Text) , "additionalProperties" .= True ] arrayOfRef :: Text -> Value arrayOfRef schemaName = object [ "type" .= ("array" :: Text) , "items" .= object ["$ref" .= ("#/components/schemas/" <> schemaName)] ] dtProp :: Value dtProp = object ["type" .= ("string" :: Text), "format" .= ("date-time" :: Text)] -- | Embedded Swagger UI HTML using CDN assets (no build step required) swaggerUiHtml :: LBS.ByteString swaggerUiHtml = LBS.fromStrict $ TE.encodeUtf8 swaggerUiHtmlText swaggerUiHtmlText :: Text swaggerUiHtmlText = "" <> "IHF API v2 \x2014 Documentation" <> "" <> "" <> "
" <> "" <> "" <> ""