Skip to main content

Configuration

The middleware is configured via a JavaScript file. In this chapter, the configuration of the middleware is explained in detail. Usually the configuration takes place in the file xemiddleware.config.mjs.

This may look like the following:

import * as mw from '@xeditor/middleware';
import * as fs from 'fs';

const packageConfig = JSON.parse(fs.readFileSync('./package.json').toString());

export const configuration = mw.defineConfiguration({
general: {
// Port the black box server runs on
host: process.env.XEDITOR_MIDDLEWARE_HOST || packageConfig.config.MIDDLEWARE_HOST,

// Port the black box server runs on
port: process.env.XEDITOR_MIDDLEWARE_PORT || packageConfig.config.MIDDLEWARE_PORT,

// Configuration for customer server that the black box server will send requests to
// (i. e. request for XML to be loaded in Xeditor)
server: {
host: process.env.XEDITOR_SERVER_HOST || packageConfig.config.SERVER_HOST,
port: process.env.XEDITOR_SERVER_PORT || packageConfig.config.SERVER_PORT
},

// Flag inditacting whether document should be validated when loading. If set to true, Raw XML editor
// will open if document was invalid.
validateOnLoad: true,

// if you applications uses wepPath prefixes, such as www.example.com/xeditor
// you can configure this here. If you application doesn't use any, you can remove this config
//
// Flag to enable/disable compression of the blackbox. Will use 'deflate' or 'gzip' for compression.
compression: true,

// Will remove the default namespace while loading (Will remove all "xmlns" attributes)
removeDefaultNamespace: false,

// can be 'Xformula' or an Object containing WIRIS configuration
mathml: 'xformula',

// Flag indicating whether SVG is used (adds additional preparations to load action)
svg: true,

// Configuration for spell checker
// In order to disable spell checking, just set the spellcheck property to false (instead of an object)
spellchecker: {
url: 'https://spellchecker.xeditor.com/v1',
username: 'xeditor',
password: 'xeditor8spellchecker'
},
},

logging: {
// used log level
// available options are `error`, `warn`, `info` and `debug`
// error: only errors will be logged (http: statusCode >= 400)
// warn: warnings and errors will be logged (http: statusCode >= 400)
// info: infos, warnings and errors will be logged (http: statusCode >= 400)
// debug: debug information and all lower levels will be logged (http: all statusCodes)
// to receive full debugging information with stacktraces process.env.XEDITOR_MIDDLEWARE_DEBUG_ENABLED has to be true
// if none of the above options is provided `info` will be used
level: 'debug',

// defines where to log the messages
// file: path to the file in which logs should be written into, if omitted no file will be created for logging
// console: true if logs should be written to console
// rfs: additional options for log file (see: https://www.npmjs.com/package/rotating-file-stream)
// path: path to the file the logs should be written to
// size: define maximum size of each log file (see: https://www.npmjs.com/package/rotating-file-stream#size)
// maxFiles: the maximum amount of log files (see: https://www.npmjs.com/package/rotating-file-stream#maxfiles)
// interval: interval in which new file should be created (see: https://www.npmjs.com/package/rotating-file-stream#interval)
// compress: flag to enable/disable compression using gzip
// if omitted completely logging will be disabled
output: {
console: true,
rfs: {
path: './logs/access.log',
size: '10M',
maxFiles: 10,
interval: '1d',
compress: true
}
}
},


// schema configuration used for validation
// DTDs and XSDs are supported
schema: {
default: 'demo@0.0',
'demo@0.0': {
file: './WEB-INF/xsd/content.xsd',
map: {
'mathml/mathml3.xsd': './WEB-INF/xsd/mathml/mathml3.xsd',
'mathml3-common.xsd': './WEB-INF/xsd/mathml/mathml3-common.xsd',
'mathml3-content.xsd': './WEB-INF/xsd/mathml/mathml3-content.xsd',
'mathml3-presentation.xsd': './WEB-INF/xsd/mathml/mathml3-presentation.xsd',
'mathml3-strict-content.xsd': './WEB-INF/xsd/mathml/mathml3-strict-content.xsd',
'svg/svg.xsd': './WEB-INF/xsd/svg/svg.xsd',
'../modules/xlink.xsd': './WEB-INF/xsd/modules/xlink.xsd',
'../modules/xml.xsd': './WEB-INF/xsd/modules/xml.xsd',
},

entities: true,
enableXpathForErrors: true,

validator: [{
type: "schematron",
config: {
typeMap: {
'structure_error': 'warn'
}
},
stylesheet: './WEB-INF/xsd/content.sch.xml'
},
{
type: "jxerify",
stylesheet: './WEB-INF/xsd/content.xsd'
}],

transformation: {
xmlToHtml: "./WEB-INF/xsl/xml_to_html_override.xsl",
htmlToXml: "./WEB-INF/xsl/html_to_xml.xsl",
officeToHtml: [
"./WEB-INF/xsl/office_to_html_1.xsl",
"./WEB-INF/xsl/office_to_html_2.xsl"
]
}
}
}
});

Using mw.defineConfiguration has the advantage that you can use intelliSense for the configuration. Thus, significantly fewer errors happen during the configuration than with normal JavaScript. For this purpose we recommend IntelliJ/Webstorm or VSCode for development.

Here the configuration is always based on the following types:

/**
* Type for Url Configuration
*/
export type URLConfiguration = {
url?: string;
} | {
host?: string;
port?: string|number;
protocol?: string;
path?: string;
} | string;

export type Transformation = {
/**
* XSLT transformations which are used for "xml to html" transformation e.g. when loading documents
*/
xmlToHtml: string | string[];

/**
* XSLT transformations which are used for "html to xml" transformation e.g. when saving documents
*/
htmlToXml: string | string[];

/**
* XSLT transformations which are used for "office to html" transformation e.g. when pasting from office
*/
officeToHtml: string | string[];
};

export type Validator = {
type: 'auto' | 'jxerify' | 'jxerify@next' | 'schematron';
config?: any;
stylesheet?: string;
};

export type Transformer = 'auto' | 'xsltproc' | {
type: 'saxon',
config: {
location: string,
config?: string
}
};

export type HookFunction<P extends HookDataArguments, R> = (data: HookData<P, R>) => R

/**
* Interface for External Configuration
*/
export interface ExternalConfiguration {
general: {
/**
* Interface to which the middleware should listen. Usually "127.0.0.1" is used for local development or "0.0.0.0" for a production system.
*/
host: string;
/**
* Port of the middleware
*/
port: string | number;
/**
* Protocol type of the middleware. If HTTPS is set, then `cert`, `ca` and `key` must also be set.
*/
protocol?: 'HTTP' | 'HTTPS';
/**
* Flag to enable Compression. Compression is used to increase speed of larger requests
*/
compression?: boolean;
/**
* Flag to enable API Documentation. If enabled, then the documentation can be accessed via `{MIDDLEWARE_ADDRESS}/api-docs`.
*/
documentation?: boolean;
/**
* Certificate which will be used for HTTPS
*/
cert?: string;
/**
* Private Key for the SSL Encription for HTTPS
*/
key?: string;
/**
* CA Certificate contains information to owner and contains it's public key for HTTPS
*/
ca?: string;

/**
* Define if formula or wiris should be used for mathML
*/
mathml?: 'xformula' | 'wiris' | false;
/**
* Flag to use SVG
*/
svg?: boolean;

/**
* Flag to enable validation on Load
*/
validateOnLoad?: boolean;

/**
* Flag to remove the default workspace
*/
removeDefaultNamespace?: boolean;

/**
* Configuration of the Server.
* Extends the URLConfiugration
*/
server: URLConfiguration & {
/**
* Type to Indicate te Media Type of the resource
*/
contentType?: 'application/json' | 'application/x-www-form-urlencoded' | 'multipart/form-data';
/**
* Flag to allow untrusted
*/
allowUntrusted?: boolean;
/**
* Flach to disable the Custom Proxy
*/
disableCustomProxy?: boolean;
};

/**
* Configuration for the Spellchecker.
* Extends the URLConfiguration
*/
spellchecker?: URLConfiguration & {
/**
* Type of the spellchecking server.
*/
type?: 'languagetool' | 'xeditor' | 'hook';

/**
* Username that should be sent to the spellchecker
*/
username?: string;

/**
* Password that should be sent to the spellchecker
*/
password?: string;
};

};

/**
* Configuration for logging
*/
logging?: {
/**
* Defines the configuration level
*/
level?: 'none' | 'debug' | 'http' | 'info' | 'warn' | 'error';

/**
* Optional filter method to filter logging output.
* @param entry
*/
filter?(entry: LogEntry): boolean;

output?: {
/**
* @param [console=false]
*/
console?: boolean;

/**
*
*/
file?: string;

/**
*
*/
rfs?: {
path: string;
size?: string;
maxFiles?: number;
interval?: string;
compress?: boolean;
}
}
};

/**
* Transformation Configuration
*/
transformation?: Transformation;

/**
* Remoteschema Configuration
*/
remoteSchema?: {
/**
* Basepath for the cache
*/
cacheBasePath?: string;
/**
* Indicate if the Hashsum should be checked
*/
checksumCheck?: boolean;
} | string;

/**
* Schema Configuration
*/
schema?: {
/**
* Name of the Schema
*/
[schemaName: string]: {
/**
* XSL or DTD File
*/
file: string;
/**
* dependencies of the XSL
*/
map?: {
[key: string]: string
};
/**
* Flag to take care about entities or not
*/
entities?: boolean;
/**
* Define which validator will be used
*/
validator?: Validator | Validator[] | Validator['type'];
/**
* Define which transformer will be used
*/
transformer?: Transformer;
/**
* Flag to set whether xpaths should be passed on errors or not.
* If true, then the xpath is evaluated and added to each error.
* his makes the validation a bit slower in case of an error, because the complete document has to be parsed.
*/
enableXpathForErrors?: boolean;
/**
* Different Transformation Files
*/
transformation: Transformation;
}
} & {
/**
* Default setting
*/
default?: string;
};

/**
* Hooks
*/
hook?: {
/**
* Init Hook
*/
inited?: HookFunction<{
application: Application,
server: Server,
port: number
}, void>;

/**
* Service Hooks
*/
service?: {
/**
* Beforeload Hook
*/
beforeload?: HookFunction<{
schema: string,
document: string
}, string | object>;

/**
* Load Hook
*/
load?: HookFunction<{
schema: string,
document: string,
validation: ValidationResult,
html: string,
xml: string,
}, string>

/**
* Meta Hook
*/
meta?: HookFunction<{
type: string
}, string>;

/**
* Beforepaste Transform Hook
*/
beforepastetransform?: HookFunction<{
document: string,
schema: string,
officeHtml: string
}, string>;

/**
* Paste Transform Hook
*/
pastetransform?: HookFunction<{
document: string,
schema: string,
officeHtml: string,
html: string
}, string>;

/**
* Before Save Hook
*/
beforesave?: HookFunction<{
document: string,
schema: string,
html: string
}, string>;

/**
* Save Hook
*/
save?: HookFunction<{
document: string,
schema: string,
html: string,
validation: ValidationResult,
xml: string,
}, string>;

/**
* Before Spellchecker get Languages Hook
*/
beforespellcheckergetlanguages?: HookFunction<{}, string>;

/**
* Spellcheckher get Languages Hook
*/
spellcheckergetlanguages?: HookFunction<{}, string>;

/**
* Before Spellchecker Check Hook
*/
beforespellcheckercheck?: HookFunction<{
text: string,
language: string
}, string>;

/**
* Spellchecker Check Hook
*/
spellcheckercheck?: HookFunction<{
text: string,
language: string,
result: Errors
}, string>;

/**
* Before Transform Hook
*/
beforetransform?: HookFunction<{
document: string,
schema: string,
format: boolean,
fromContent: string,
from: string,
to: string,
}, string>;

/**
* Transform Hook
*/
transform?: HookFunction<{
document: string,
schema: string,
format: boolean,
fromContent: string,
from: string,
toContent: string,
to: string
}, string>;

/**
* Before Validate Hook
*/
beforevalidate?: HookFunction<{
schema: string,
document: string,
xml: string,
format: boolean
}, ValidationResult>;

/**
* Validate Hook
*/
validate?: HookFunction<{
schema: string,
document: string,
xml: string,
format: boolean,
validation: ValidationResult
}, string>;

},

/**
* Data Hooks
*/
data: {
/**
* Health Hook
*/
health?: HookFunction<{
status: string,
timestamp: number,
pong: string|undefined
}, string>;

/**
* get XML Hook
*/
getxml?: HookFunction<{
document: string,
schema: string
}, string>;

/**
* set XML Hook
*/
setxml?: HookFunction<{
document: string,
schema: string,
html: string,
validation: ValidationResult,
xml: string,
}, string>;

schema?: {
/**
* Schema Hook
*/
verify?: HookFunction<{
name: string,
schema?: Schema
}, VerificationResult>;

/**
* Schema Hook
*/
load?: HookFunction<{
name: string,
schema?: Schema
}, Schema>;
}

spellchecker?: {
languages?: HookFunction<{}, Languages>;

check?: HookFunction<{
text: string,
language: string
}, Errors>;
}
/**
* Resolveentity Hook
*/
resolveentity?: HookFunction<{
id: string,
type: 'attribute' | 'element',
node: Node,
entity: string,
value: string,
valueResolver: Promise<string>
}, Schema>;

/**
* Stylesheets Hook
*/
stylesheets?: HookFunction<{
data: any
}, Schema>;
},

/**
* Transform Hooks
*/
transformer?: {
/**
* Transform Hook
*/
beforetransform?: HookFunction<{
data: any
}, Schema>;

/**
* Transform Hook
*/
transform?: HookFunction<{
data: any
}, Schema>;
},

/**
* Validator Hooks
*/
validator?: {
/**
* Before Validate Hook
*/
beforevalidate?: HookFunction<{
data: any,
value: string
}, Schema>;

/**
* Validate Hook
*/
validate?: HookFunction<{
data: any
value: string,
result: ValidationResult
}, Schema>;

/**
* Dispose Hook
*/
dispose?: HookFunction<{
data: any
}, void>;
}
};
}