Design Hub developer guide - registry plugins

    Design Hub's registry plugins are a collection of API endpoints that facilitate integrating the application into an organization's substance registry and related workflows:

    As described below in the specification, the 2 approaches follow the same concepts, and internally are managed by the same service, so outgoing call arguments are the same regardless of the technical choice, and your plugin's configuration will have identical behaviour in the application regardless of the API.

    NodeJS module API

    Registry plugins are NodeJS modules, denoted by their filename: *.registry.js and location in the services directory as configured during installation.

    A registry plugin exports the following properties:

    Name Type Required Description
    name string yes Unique identifier of the plugin, used by Design Hub for identification and internal communication. If multiple plugins use the same identifier, the last one to be loaded overrides the others.
    label string yes Human readable name of the plugin, used by Design Hub to display GUI elements related to this plugin.
    checkCompound async function no Called when a user attempts to share a compound. This function may return drawing quality issues regarding the 2D structure of the compound.

    Arguments:
    structure (string) An MRV formatted chemical structure
    this includes domain for the current call

    Return value: Promise of an object. The object must include an array of strings under the issues key. Each string corresponds to one drawing quality issue, e.g.: Unspecified stereo centers.
    getID async function no Called when a user attempts to share a compound, and then periodically depending on configuration, until a substance ID is found for the compound. This function may return a single identifier for a compound from a small molecule registration system. To control the periodicity of function calls, please see the schedulerPlan option in the Configuration guide

    Arguments:
    structure (string) MRV formatted chemical structure
    this includes domain and user

    Return value: Promise of an optional string. The string must contain the substance ID for the chemical structure. Empty string (or null, undefined) are treated as successful queries without a hit.
    getMatches async function no Called when a user attempts to share a compound, and then periodically depending on configuration, until substances matches are found for the compound. This function can return one or more objects describing matching compounds from a small molecule registration system. To control the periodicity function calls, please see the schedulerPlan option in the Configuration guide

    Arguments:
    queryObject (object). See description below.
    this includes domain and user

    Return value: Promise of a list of substance matches. Each substance match must contain: id (string), structure (string) and data (object)
    domains array of strings yes List of domains where this plugin may be used, when authentication is enabled in Design Hub. Use * to allow any domain.
    onConfigurationChanged function no A callback function that Design Hub calls during initialization and whenever an administrator updates the Secrets of the system.

    Arguments:
    config (Object) An object with secrets attribute containing the key-value pairs of secrets from the Admin interface

    Note: you may use _development authentication type to test aspects of your plugin specific to a domain. This authentication type accepts any username, password combination, where the 2 field string match.

    Mapping between virtual compounds and substances

    Exact matching

    When it is expected that at most one substance matches a virtual compound, Design Hub may be left in its default configuration. For avoidance of doubt, these configuration options are necessary:

    1. matchLogic - using the registry.matchLogic configuration key, make sure the system is in an automatic configuration. This leads to Design Hub using the getID API of the registry plugin.
    2. getID - by implementing this registry plugin API call, Design Hub will periodically check and expect a single Substance ID to be returned whenever a chemical structure is eventually registered.

    Flexible matching

    When it is expected that multiple substances - stereoisomers, salt forms, conjugates, or simply additional batches - relate to the same virtual compound, Design Hub can be configured accordingly. Furthermore, to allow restricting potentially matching substances from the UI, Design Hub may be configured to use custom compound fields during the matches. For this purpose, several configuration options are necessary:

    1. matchLogic - using the registry.matchLogic configuration key, make sure the system is in a multi match configuration. This leads to Design Hub using the getMatches API of the registry plugin. See configuration guide.
    2. compoundFields - optionally, using the compoundFields configuration key, define custom fields that may be necessary for storing (both user input and programmatic updates) metadata of matching substances.
    3. checkCSTFields - optionally, using the registry.checkCSTFields configuration key, specify the name of custom compoundFields whose value should be passed as optional arguments in getMatches API calls.
    4. copyCSTFields - optionally, using the registry.copyCSTFields configuration key, and the data attribute of getMatches response objects, define which values to save when users approve a substance match.
    5. getMatches - finally, by implementing this registry plugin API call, Design Hub will periodically check and expect a list of matching substances whenever assets are registered.

    Plugin skeleton

    config.json

    {
      ...
      "registry": {
        "matchLogic": "multi",
        "checkCSTFields": ["fieldName"],
        "copyCSTFields": ["fieldName"]
        ...
      },
      "compoundFields": [
        {
          "name": "fieldName",
          "label": "Field Label",
          "type": "enum",
          "values": ["Value 1", "Value 2"]
        },
      ]
      ...
    }

    skeleton.registry.js

    //@ts-check
    "use strict";
    
    const dhutils = require("@chemaxon/dh-utils");
    
    /**
     *
     * @typedef {Object} RegistryPluginContext
     * @prop {User} user
     * @prop {string} domain
     * 
     * @typedef {Object} RegistryPluginQuery
     * @prop {string} structure
     * @prop {{[key: string]: string|number}} [cstData]
     * 
     * @typedef {Object} SubstanceMatch
     * @prop {string} id
     * @prop {string} structure
     * @prop {{[key: string]: string|number}} [data]
     *
     * @typedef {Object} User
     * @prop {string} userName
     * @prop {any} tokens OIDC TokenSet
     * 
     */
    
    /**
     * Find all matching compounds
     * @this {RegistryPluginContext}
     * @param {RegistryPluginQuery} queryObject
     * @returns {Promise<SubstanceMatch[]>}
     */
    async function getMatches(queryObject) {
        const mol = await dhutils.convert(queryObject.structure, "mol:-a");
      console.log(queryObject.cstData?.fieldName);
    
        //perform queries
    
        return [{
        id: "",
        structure: "",
        data: {
          fieldName: "Value 1"
        }
      }];
    }
    
    /**
     * Find exact matches of this compound
     * @this {RegistryPluginContext}
     * @param {string} structure
     * @returns {Promise<string | undefined>}
     */
    async function getID(structure) {
        const mol = await dhutils.convert(structure, "mol:-a");
    
        //perform queries 
    
        return "";
    }
    
    module.exports = {
        name: "skeleton-registry",
        label: "Skeleton Registry",
        getMatches: getMatches,
        getID: getID,
        domains: ["*"]
    };