Gathering detailed insights and metrics for @openmrs/esm-module-config
Gathering detailed insights and metrics for @openmrs/esm-module-config
Gathering detailed insights and metrics for @openmrs/esm-module-config
Gathering detailed insights and metrics for @openmrs/esm-module-config
The core modules of the OpenMRS 3.0 Frontend system
npm install @openmrs/esm-module-config
Typescript
Module System
Node Version
NPM Version
TypeScript (90.59%)
SCSS (5.67%)
JavaScript (3.05%)
Shell (0.36%)
EJS (0.27%)
Dockerfile (0.06%)
Total Downloads
0
Last Day
0
Last Week
0
Last Month
0
Last Year
0
NOASSERTION License
73 Stars
1,745 Commits
248 Forks
59 Watchers
20 Branches
192 Contributors
Updated on Jul 12, 2025
Latest Version
0.2.0
Package Id
@openmrs/esm-module-config@0.2.0
Size
56.47 kB
NPM Version
6.13.4
Node Version
12.16.1
Published on
Sep 30, 2020
Cumulative downloads
Total Downloads
Last Day
0%
NaN
Compared to previous day
Last Week
0%
NaN
Compared to previous week
Last Month
0%
NaN
Compared to previous month
Last Year
0%
NaN
Compared to previous year
1
This is the configuration library for OpenMRS Microfrontends. It makes configurability easier for developers and configuring easier for implementers.
OpenMRS frontend configuration files are JSON files containing module names as top-level elements. All configuration elements are optional. The available configuration elements for each module should be documented in the module's wiki page.
Here's an example!
1{ 2 "@openmrs/esm-login-app": { 3 "logo": { 4 "src": "https://pbs.twimg.com/media/C1w_czvWgAAWONL.jpg" 5 } 6 }, 7 "@openmrs/esm-home-app": { 8 "buttons": { 9 "enabled": false 10 } 11 } 12}
Alternatively you can provide your config file as a Javascript file. It will look just about the same, but with some magic words at the beginning:
1exports = {}; 2exports.default = { 3 "@openmrs/esm-login-app": { 4 logo: { 5 src: "https://pbs.twimg.com/media/C1w_czvWgAAWONL.jpg" 6 } 7 }, 8 "@openmrs/esm-home-app": { 9 buttons: { 10 enabled: false 11 } 12 } 13}
There are two methods for doing so.
Upload your configuration file and add its URL to
your import map as a module named config-file. If you are serving your
microfrontends from your OpenMRS server, you can simply add your config
file to your server's frontend/
directory. Your import map will then look like
1{ 2 "imports": { 3 "config-file": "/openmrs/frontend/config.js[on]" 4 } 5}
Due to RFC-26 this method will not work as described with openmrs-module-spa after 1.0.6. Please hang tight while we work out how to support hierarchal config files in the new architecture.
This method requires you have an esm-root-config override. This allows you to have multiple configuration files, which will be merged together in an order that you specify. You add your configuration files to your root override module, import them, and provide them to esm-module-config. All this must happen before you register your applications.
Example code:
1import { provide } from "@openmrs/esm-module-config"; 2 3import pihConfig from "./pih-config.json"; 4import pihMexicoConfig from "./pih-mexico-config.json"; 5 6provide(pihConfig); 7provide(pihMexicoConfig);
All provided configs will be merged, with elements provided by later calls
to provide taking priority. The import map config file, config-file
, will
also be merged, and will take the lowest priority. In the above example,
configuration elements in pih-mexico-config.json
will take priority over
those in pih-config.json
.
You can break up your configuration files into hierarchies, or per module, or per groups of modules.
You should use this module, esm-module-config, to make your modules configurable.
Start by npm install --save @openmrs/esm-module-config
. This is a runtime
dependency, so it should be included in your webpack externals
.
The main task is to create a config schema for your module. The config schema
is what tells esm-module-config
what configuration files should look like,
including defaults and validations.
You'll probably start with some idea of what you want configs for your module to look like. Try and put yourself in the implementer's shoes an imagine what features they will expect to be configurable, and what they might expect the configuration property to be called. Assume they don't know anything about the internal workings of your module.
By way of example, let's say we're building a module for a virtual provider functionality at a very futuristic hospital. Maybe we want an implementer to be able to write the following in their config file:
1"@openmrs/esm-hologram-doctor": { 2 "hologram": { 3 "color": true 4 }, 5 "virtualProvider": { 6 "name": { 7 "given": ["Qui", "Gon"] 8 } 9 }, 10 "robots": [ 11 { "name": "R2-D2", "homeworld": "Naboo" }, 12 { "name": "BB-8", "homeworld": "Hosnian Prime" } 13 ] 14}
In the following section, we'll see how to write a config schema that supports these config elements.
We'll start with just that first nested config element from above, hologram.color
. We must provide defaults for all of the values—in OpenMRS Microfrontends, all configuration is optional.
1import { defineConfigSchema, validators, validator } from "@openmrs/esm-module-config" 2 3defineConfigSchema("@openmrs/esm-hologram-doctor", { 4 hologram: { 5 color: { 6 default: false, 7 validators: [validators.isBoolean], 8 description: "Whether the cologram supports color display." 9 } 10 } 11}
Note that each configuration element should have an object for a value, and that this object must define the default for that element. Do not do this:
1❌ // This is wrong!
2❌ defineConfigSchema("@openmrs/esm-hologram-doctor",
3❌ hologram: {
4❌ salutation: "Some friendly default salutation! ? this is wrong!"
5❌ })
The following names are reserved and cannot be used as config keys:
default
, validators
, description
, and arrayElements
. Doing so
will result in undefined behavior. Do not do this:
1❌ // Don't do this! 2❌ defineConfigSchema("@openmrs/esm-hologram-doctor", 3❌ hologram: { 4❌ salutation: { 5❌ default: { 6❌ default: "Greetings ? this is bad don't do it" 7❌ }}})
You should provide validators for your configuration elements wherever possible. This reduces the probability that implementers using your module will have hard-to-debug runtime errors. It gives you, the module developer, the opportunity to provide implementers with very helpful explanations about why their configuration on't work.
1robot: { 2 name: { 3 default: "R2D2", 4 validators: [ 5 validators.isString, 6 validator(n => /\d/.test(n), "Robots must have numbers in their names") 7 ] 8 } 9}
(Note that this piece of schema is not part of our above example. It only supports a single robot, whereas we need to allow the implementer to provide an array of robots).
A validator can be created using the validator
function, as above.
The first argument is a function that takes the config value as its only argument. If the function returns something truthy, validation passes. If the function returns something falsy, an error is thrown with the second argument as an explanation.
You can even validate nested objects:
1colorPicker: { 2 options: { default: ["black", "red"] } 3 initial: { default: "black" }, 4 validators: [ 5 validator(o => o.options.includes(o.initial), 6 "initial must be one of the options") 7 ] 8}
For convenience, some common validators are provided out of the box. See the API / validators.
You can accept and validate arrays, and arrays containing objects, in your
configuration schema. This is configured with the arrayElements
parameter. For
example, a schema which would accept an array of strings:
1virtualProvider: { 2 name: { 3 given: { 4 default: ["Obi", "Wan"] 5 arrayElements: { 6 validators: [validators.isString] 7 } 8 } 9 } 10}
Here is an example of a schema that expects an array of objects structured in a particular way.
1robots: { 2 default: [ 3 { name: "R2-D2", homeworld: "Naboo" }, 4 { name: "C-3PO", homeworld: "Tatooine" } 5 ], 6 arrayElements: { 7 name: { validators: [robotNameValidator] }, 8 homeworld: { 9 default: null // not required 10 validators: [validators.isString] 11 } 12 } 13}
This schema will require that any objects in the robots array must only have
the keys name
and homeworld
.
In unusual scenarios you might want to accept an object without validating its keys. To do this, you can specify the config element like a normal non-object element.
1beepsPerRobot: { 2 default: { 3 "R2-D2": 4, 4 "C-3P0": 0 5 }, 6 validators: [ // you can (and should) still run validators 7 validators.isObject, 8 validator(o => Object.values(o).every(Number.isInteger), 9 "robot beeps must be integers") 10 ] 11}
The config is fetched asynchronously using getConfig(moduleName)
. Continuing the
above example, we would have something like
1import { getConfig } from "@openmrs/esm-module-config" 2 3async function doctorGreeting() { 4 const config = await getConfig("@openmrs/esm-hologram-doctor") 5 return "Hello, my name is Dr. " + config.virtualProvider.name.family 6}
The content of config will be pulled from the config files, falling back to the defaults for configuration elements for which no values have been provided.
A React Hook is provided to hide the asynchronicity of config loading. The
moduleName
provided to the
openmrs react root decorator
is used to look up the configuration elsewhere in the application.
1export default openmrsRootDecorator({ 2 featureName: "hologram doctor", 3 moduleName: "@openmrs/esm-hologram-doctor" 4})(Root)
You can then get the config tree as an object using the useConfig
React hook.
1import { useConfig } from "@openmrs/esm-module-config" 2 3export default function DoctorGreeting() { 4 const config = useConfig() 5 const greeting = "Hello, my name is Dr. " + config.virtualProvider.name.family 6 return <div>{greeting}</div> 7}
The content of config will be pulled from the config files, falling back to the defaults for configuration elements for which no values have been provided.
This hasn't been implemented yet, but we would like to implement it! See "Contributing"
Const
ModuleNameContext• ModuleNameContext: Context‹null | string› = React.createContext<string | null>(null)
Defined in react-hook/react-hook.tsx:4
▸ ConfigurableLink(__namedParameters
: object): Element‹›
Defined in navigation/react-configurable-link.tsx:13
A React link component which calls navigate when clicked
Parameters:
▪ __namedParameters: object
Name | Type | Description |
---|---|---|
children | any | Inline elements within the link |
otherProps | otherProps | Any other valid props for an tag except href and onClick |
to | string | The target path or URL. Supports interpolation. See navigate |
Returns: Element‹›
▸ interpolateString(template
: string, params
: object): string
Defined in navigation/interpolate-string.ts:38
Interpolates values of params
into the template
string.
Useful for additional template parameters in URLs.
Example usage:
1navigate({
2 to: interpolateString(
3 config.links.patientChart,
4 { patientUuid: patient.uuid }
5 )
6});
Parameters:
Name | Type | Description |
---|---|---|
template | string | With optional params wrapped in ${ } |
params | object | Values to interpolate into the string template |
Returns: string
▸ navigate(__namedParameters
: object): void
Defined in navigation/navigate.ts:24
Calls location.assign
for non-SPA paths and navigateToUrl for SPA paths
Example usage:
1const config = getConfig(); 2const submitHandler = () => { 3 navigate({ to: config.links.submitSuccess }); 4};
Parameters:
▪ __namedParameters: object
Name | Type | Description |
---|---|---|
to | string | The target path or URL. Supports templating with 'openmrsBase' and 'openmrsSpaBase'. For example, ${openmrsSpaBase}/home will resolve to /openmrs/spa/home for implementations using the standard OpenMRS and SPA base paths. |
Returns: void
▸ defineConfigSchema(moduleName
: string, schema
: ConfigSchema): void
Defined in module-config/module-config.ts:20
Parameters:
Name | Type |
---|---|
moduleName | string |
schema | ConfigSchema |
Returns: void
▸ getConfig(moduleName
: string): Promise‹ConfigObject›
Defined in module-config/module-config.ts:29
Parameters:
Name | Type |
---|---|
moduleName | string |
Returns: Promise‹ConfigObject›
▸ processConfig(schema
: ConfigSchema, providedConfig
: ConfigObject, keyPathContext
: string): Config
Defined in module-config/module-config.ts:42
Validate and interpolate defaults for providedConfig
according to schema
Parameters:
Name | Type | Description |
---|---|---|
schema | ConfigSchema | a configuration schema |
providedConfig | ConfigObject | an object of config values (without the top-level module name) |
keyPathContext | string | a dot-deparated string which helps the user figure out where the provided config came from |
Returns: Config
▸ provide(config
: Config, sourceName
: string): void
Defined in module-config/module-config.ts:25
Parameters:
Name | Type | Default |
---|---|---|
config | Config | - |
sourceName | string | "provided" |
Returns: void
▸ useConfig(): any
Defined in react-hook/react-hook.tsx:8
Returns: any
▸ validator(validationFunction
: ValidatorFunction, message
: string): Validator
Defined in validators/validator.ts:1
Parameters:
Name | Type |
---|---|
validationFunction | ValidatorFunction |
message | string |
Returns: Validator
Const
validatorsDefined in validators/validators.ts:66
• isBoolean: function
Defined in validators/validators.ts:69
▸ (value
: any): void | string
Parameters:
Name | Type |
---|---|
value | any |
• isNumber: function
Defined in validators/validators.ts:68
▸ (value
: any): void | string
Parameters:
Name | Type |
---|---|
value | any |
• isObject: function
Defined in validators/validators.ts:71
▸ (value
: any): void | string
Parameters:
Name | Type |
---|---|
value | any |
• isString: function
Defined in validators/validators.ts:67
▸ (value
: any): void | string
Parameters:
Name | Type |
---|---|
value | any |
• isUrl: function
Defined in validators/validators.ts:72
▸ (value
: any): void | string
Parameters:
Name | Type |
---|---|
value | any |
• isUrlWithTemplateParameters: isUrlWithTemplateParameters
Defined in validators/validators.ts:73
• isUuid: function
Defined in validators/validators.ts:70
▸ (value
: any): void | string
Parameters:
Name | Type |
---|---|
value | any |
PRs welcome! See OpenMRS Microfrontends RFC-20 for guidelines about contributing.
Setup local development environment for OpenMRS SPA.
Maintainer: Brandon Istenes (bistenes@pih.org)
No vulnerabilities found.
Reason
30 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 10
Reason
no dangerous workflow patterns detected
Reason
no binaries found in the repo
Reason
packaging workflow detected
Details
Reason
SAST tool is run on all commits
Details
Reason
Found 27/30 approved changesets -- score normalized to 9
Reason
license file detected
Details
Reason
no effort to earn an OpenSSF best practices badge detected
Reason
security policy file not detected
Details
Reason
detected GitHub workflow tokens with excessive permissions
Details
Reason
project is not fuzzed
Details
Reason
dependency not pinned by hash detected -- score normalized to 0
Details
Reason
24 existing vulnerabilities detected
Details
Score
Last Scanned on 2025-07-07
The Open Source Security Foundation is a cross-industry collaboration to improve the security of open source software (OSS). The Scorecard provides security health metrics for open source projects.
Learn More