/**
* @fileoverview xOpat Static configuration: 'ENV'
* @typedef xoEnv
*/
{ /**@lends xoEnv */
/* General xOpat Metadata */
"name": "xOpat",
/* Version is overrideable on deployment level */
"version": null,
/* Where xOpat redirects the user in case of error */
"gateway": "../",
/* Active configuration in the "client" */
"active_client": "dev",
/**
* The Client App static configuration
* @typedef {{
* domain: string,
* path: string,
* slide_protocols: Object.<string, string>,
* default_background_protocol: string,
* default_visualization_protocol: string,
* image_group_server: string,
* image_group_protocol: string,
* data_group_server: string,
* data_group_protocol: string,
* osdOptions: ?Object,
* js_cookie_expire: ?number,
* js_cookie_path: ?string,
* js_cookie_same_site: ?string,
* js_cookie_secure: ?boolean,
* secureMode: ?boolean,
* production: ?boolean
* }} xoClientSetup
*
* Slide protocols: each `slide_protocols[name]` is a backtick-template URL with
* `data` (scalar DataID) in scope. The server URL is embedded directly in the
* template — no separate server map. `default_background_protocol` /
* `default_visualization_protocol` pick the protocol used for background and
* visualization images respectively. `BackgroundItem.protocol` /
* `DataOverride.protocol` may reference any registered name — safe in secure
* mode (no eval of user input).
*
* Plugins can register additional protocols at runtime via
* `window.SLIDE_PROTOCOLS.register(...)`, including factory protocols that
* build a TileSource directly (see the dicom plugin).
*
* Entries may also use the object form
* `"name": { "url": "<template>", proxy?, auth?, headers?, timeoutMs?, … }`
* to declare HttpClient options. When present, all requests from that
* protocol's TileSource (metadata + tiles) flow through the configured
* client, gaining proxy routing, CSRF, and JWT/auth headers uniformly.
*
* `image_group_*` / `data_group_*` keys are DEPRECATED legacy fields kept for
* backward compatibility; auto-synthesized into `__legacy_bg` / `__legacy_viz`
* entries on load when `slide_protocols` is missing. Note: legacy
* `data_group_protocol` receives `data` as an array (`data.join(",")` contract);
* new entries above always receive scalar.
*/
"client": {
"dev": {
/* The Viewer Domain Full URL including protocol NOTE: should end with a slash */
"domain": "http://localhost:8080/",
/*
The Path to the Viewer at given domain, so that 'domain+path+index.php' is the viewer index.
Use null to let the system detect the path automatically.
*/
"path": "",
/*
Slide protocol registry. See xoClientSetup typedef above for the full
contract. Each entry resolves a DataID into a tile-source URL via a
backtick template with `data` (scalar) in scope; the server URL is
embedded directly in the template. Names referenced from
`BackgroundItem.protocol` / `DataOverride.protocol` are safe in
secure mode (no eval of user-controlled strings).
*/
"slide_protocols": {
"iip_deepzoom": "`/iipsrv/iipsrv.fcgi?Deepzoom=${data}.dzi`",
"iip_deepzoom_ext": "`/iipsrv/iipsrv.fcgi#DeepZoomExt=${data}.dzi`"
//"secure_wsi": {
// "url": "`/v3/slides/info?slide_id=${data}`",
// "proxy": "wsi-proxy",
// "auth": { "contextId": "wsi", "types": ["jwt"], "required": true }
//}
},
"default_background_protocol": "iip_deepzoom",
"default_visualization_protocol": "iip_deepzoom_ext",
/*
Legacy keys — DEPRECATED, kept for backward compatibility during the
registry rollout. Auto-synthesized into `__legacy_bg` / `__legacy_viz`
entries if `slide_protocols` is missing. Note: `data_group_protocol`
historically receives `data` as an array (`data.join(",")` contract);
new entries above always receive scalar.
*/
"image_group_server": "/iipsrv/iipsrv.fcgi",
"image_group_protocol": "`${path}?Deepzoom=${data}.dzi`",
"data_group_server": "/iipsrv/iipsrv.fcgi",
"data_group_protocol": "`${path}#DeepZoomExt=${data.join(\",\")}.dzi`",
/* Cookie Setup */
"js_cookie_expire": 365,
"js_cookie_path": "/",
"js_cookie_same_site": "", //string value, lowercase
"js_cookie_secure": false, //boolean - true/false
"js_cookie_domain": null, //by default the viewer domain
"secureMode": false,
/* Production mode (serve minified files if available) */
"production": false,
/*
* Server-side plugin selection mode. Controls which plugins
* (and modules) the server ships to the client.
* "all" - every plugin without `enabled: false` is shipped
* (default, current behavior).
* "whitelist" - only plugins explicitly opted in via the
* deployment ENV (`plugins.<id>.enabled = true`)
* are shipped. A plugin's own include.json
* `enabled: true` does NOT whitelist it. Modules
* are dependencies pulled in by plugins and are
* not whitelisted independently.
* "available" - like "all", plus each plugin / module may
* declare a single `requiredConfig: ["dot.path", ...]`
* array in include.json. Each path is resolved
* against TWO deployment-controlled sources:
* 1. ENV.plugins[id] / ENV.modules[id]
* (env.json top-level `plugins`/`modules`)
* 2. server.secure.plugins[id] / server.secure.modules[id]
* (env.json `core.server.secure`, never
* shipped to the client — the natural home
* for secret-adjacent values).
* A path is satisfied if EITHER source carries
* a non-undefined/null/empty value. Include.json
* defaults are NOT consulted. The plugin author
* declares *what* is needed; the admin decides
* *where* each value lives based on sensitivity.
* Missing-path elements are silently dropped.
*/
"pluginSelectionMode": "all",
/* OpenSeadragon.Options to pass, some values are overridden as necessary. */
"osdOptions": {
"crossOriginPolicy": "Anonymous"
}
/*
* Generic IO pipeline admin block. Routes plugin/module bundle &
* CRUD capabilities to sinks (file-download, http-rest, github, …)
* and ships per-deployment options to those sinks. The pipeline
* captures this block at boot — server-only, never URL-modifiable.
* Full reference: src/IO_PIPELINE.md.
*/
//"io": {
// /* Hard-disable IO for these owners (highest precedence). */
// //"disabled": ["some-plugin-id"],
//
// /*
// * Per-deployment sink options keyed by sink id. Each owning
// * module composes these with its own defaults inside the sink
// * factory's getOptions callback. Secrets do NOT belong here —
// * keep them in server.secure.proxies.<alias> instead.
// */
// "sinkOverrides": {
// /* GitHub bundle sink (modules/io-github-sink). */
// //"github": {
// // "repo": "your-org/xopat-state",
// // "branch": "main",
// // /* Path placeholders: {ownerId} {ownerUid} {viewerId} {capabilityId} {xoType}. */
// // "pathTemplate": "xopat/{ownerId}/{viewerId}.json",
// // "commitMessageTemplate": "xopat: sync {ownerId} {viewerId}",
// // "committer": { "name": "xOpat Bot", "email": "bot@example.org" },
// // /* Forwarded to HttpClient verbatim — drop if proxy has auth.enabled:false. */
// // "auth": { "contextId": "core", "types": ["jwt"], "required": true }
// //},
// /* Generic HTTP REST sink (built-in). */
// //"http-rest": {
// // "proxy": "my-service",
// // "baseURL": "/api/v1/objects",
// // "auth": { "contextId": "core", "types": ["jwt"], "required": true }
// //}
// },
//
// /*
// * Bindings keyed by ownerId (the include.json `id` field) and
// * capabilityId (advertised in include.json io.capabilities).
// * Multiple sinks can serve one capability — listed in dispatch
// * order. Empty array disables the capability for that owner.
// */
// "bindings": {
// "annotations": {
// "bundle-export": ["github", "file-download"],
// "bundle-import": ["github"],
// "crud:annotation": [],
// "crud:preset": []
// },
// "core": {
// "bundle-export": ["post-data"]
// }
// }
//}
},
// We can keep multiple configurations within the file and switch between them...
"prod": {
"domain": "https://rationai-vis.ics.muni.cz/",
"path": null,
/* New-style registry; see dev block above for shape. */
"slide_protocols": {
"iip_deepzoom": "`/iipsrv/iipsrv.fcgi?Deepzoom=${data}.dzi`",
"iip_deepzoom_ext": "`/iipsrv/iipsrv.fcgi#DeepZoomExt=${data}.dzi`"
},
"default_background_protocol": "iip_deepzoom",
"default_visualization_protocol": "iip_deepzoom_ext",
/* Legacy (deprecated) — kept for backward compatibility. */
"image_group_server": "/iipsrv/iipsrv.fcgi",
"image_group_protocol": "`${path}?Deepzoom=${data}.dzi`",
"data_group_server": "/iipsrv/iipsrv.fcgi",
"data_group_protocol": "`${path}#DeepZoomExt=${data.join(\",\")}.dzi`",
"js_cookie_expire": 365,
"js_cookie_path": "/",
"js_cookie_same_site": "strict",
"js_cookie_secure": true,
"js_cookie_domain": null,
"secureMode": true,
"production": true,
/* See "pluginSelectionMode" in the "dev" block above for the full reference. */
"pluginSelectionMode": "all",
"osdOptions": {
"crossOriginPolicy": "Anonymous"
}
}
},
/**
* The Viewer Default Settings, all overrideable through params configuration.
* @typedef {{
* sessionName: ?string,
* locale: ?string,
* customBlending: ?boolean,
* debugMode: ?boolean,
* webglDebugMode: ?boolean,
* scaleBar: ?boolean, // deprecated alias of ui.scaleBar
* toolBar: ?boolean, // deprecated alias of ui.toolBar
* statusBar: ?boolean, // deprecated alias of ui.statusBar
* ui: ?{
* scaleBar: ?boolean,
* toolBar: ?boolean,
* statusBar: ?boolean,
* mainMenu: ?boolean,
* navigator: ?boolean,
* appBar: ?boolean,
* },
* viewport: ?Object,
* activeBackgroundIndex: ?number,
* activeVisualizationIndex: ?number,
* grayscale: ?boolean,
* tileCache: ?boolean,
* preventNavigationShortcuts: ?boolean,
* permaLoadPlugins: ?boolean,
* theme: ?string,
* maxImageCacheCount: ?number,
* webGlPreferredVersion: ?string,
* bypassCache: ?boolean,
* bypassCookies: ?boolean,
* bypassCacheLoadTime: ?boolean,
* disablePluginsUi: ?boolean,
* disablePluginsAutoload: ?boolean,
* valueInspectorEnabled: ?boolean,
* visualizationInspectorEnabled: ?boolean,
* visualizationInspectorMode: ?string,
* visualizationInspectorRadiusPx: ?number,
* visualizationInspectorLensZoom: ?number
* }} xoParams
*/
"setup": {
//viewer session name/ID, can be overridden on background-level configuration
"sessionName": null,
// depends on available locales in locales/ folder
"locale": "en",
"customBlending": false,
"debugMode": false,
"webglDebugMode": false,
/* Deprecated flat aliases; new code should write to `ui.*` below. Kept for back-compat. */
"scaleBar": true,
"toolBar": true,
"statusBar": true,
/*
Initial visible state of UI components. `false` boots the component
collapsed but the user can still toggle it back via settings or the
hide-UI button. See `XOpatUiSetup` in `src/types/config.d.ts` for
the full contract.
*/
"ui": {
"scaleBar": true,
"toolBar": true,
"statusBar": true,
"mainMenu": true,
"navigator": true,
"appBar": true,
"globalMenu": true
},
// default background color, a hex RGB or RGBA
"backgroundColor": null,
// todo consider moving multiple params to the viewer-dependent configuration
// object that has {"zoomLevel":<zoom>,"point":{"x":<x>,"y":<y>}} default viewport position definition
// point is in the viewport coordinate system of OpenSeadragon
"viewport": null,
// default active indexes for image (background) and data (visualization) group
"activeBackgroundIndex": 0,
"grayscale": false,
"tileCache": true,
"preventNavigationShortcuts": false,
// require Ctrl/Cmd + wheel to zoom the viewer — plain wheel falls through
// to the host page. Recommended for notebook / scrollable-host embeddings.
"scrollRequiresCtrl": false,
"permaLoadPlugins": true,
// suppress the browser's "Leave site?" prompt when there are unsaved changes
"bypassCloseConfirmation": false,
// can disable cookies support
"bypassCookies": false,
// can disable cache data loading
"bypassCache": false,
"bypassCacheLoadTime": false,
// "auto" (follows the OS preference), "dark" or "light".
"theme": "auto",
"maxImageCacheCount": 1200,
// can be only 2.0 for now
"webGlPreferredVersion": "2.0",
// deprecated
"preferredFormat": "zip",
// Do not render plugin selection in GUI, but they can still be active
"disablePluginsUi": false,
// If true, the _plugins cookie restore is skipped this session.
// permaLoad plugins and session-declared plugins still load.
"disablePluginsAutoload": false,
"valueInspectorEnabled": false,
"visualizationInspectorEnabled": false,
"visualizationInspectorMode": "reveal-inside",
"visualizationInspectorRadiusPx": 96,
"visualizationInspectorLensZoom": 2,
// Renders viewer in standalone mode, all data is static (leave as false if unsure)
"isStaticPreview": false,
"historySize": 50,
"maxMobileWidthPx": 900,
"globalMenuMaxWidth": 1200,
"notificationsPosition": "bottom"
},
/**
* The Server configuration. This object is here just for the reference and
* to provide default values; the server shall set up these properties accordingly.
* @typedef {{
* name: string,
* supportsPost: boolean
* }} xoServerConfig
*/
"server": {
"name": null,
// Disable for servers that do not support POST parsing: will not support direct data sharing
"supportsPost": true,
// EVERYTHING in the config.js (env.json, XO_ENV) is AVAILABLE AND READABLE at client-server.
// The only thing that is not readable is this part - this stays on the server.
// If you have some secret you MUST NOT expose at any cost, do your logics
// via proxying and use your secrets in the 'secure' part of the server configuration.
"secure": {
// The server supports url+header configuration for custom proxies. You can
// - configure module/plugin to use local proxy endpoint
// - configure the proxy here
// Request headers belong only here in secure server config, never in viewer/session params.
"proxies": {
// My proxy service will proxy a resource using token that is NOT exposed on the client.
//"my-service": {
// "baseUrl": "https://api.example.com",
// "headers": {
// "Authorization": "Bearer <% MY_SERVICE_TOKEN %>"
// },
// // The proxy service can explicitly VERIFY the user has necessary rights to call the endpoint
// // Supported verifiers are: 'jwt'
// "auth": {
// "enabled": true,
// "mode": "all" // "all" (default) or "any" - all or any verifier must pass
// // From now on, other configuration depends on the actual verifier used, see HTTP Client
// "verifiers": {
// "jwt": {
// "secret": "<% YOU_CAN_READ_ENV_OR_ADD_STATIC_VALUE %>",
// "issuer": "https://login.example.com/",
// "audience": "xopat-viewer",
// "forward": false,
// "userClaimHeader": "x-user-sub"
// }
// }
// }
//},
//
// Server-side counterpart for the `github` IO sink (modules/io-github-sink).
// The fine-grained PAT lives ONLY here; the browser only sees the alias.
// Pair with `client.<env>.io.sinkOverrides.github` above.
//"github": {
// "baseUrl": "https://api.github.com/", // for GHE: "https://<host>/api/v3/"
// "headers": {
// "Authorization": "Bearer <% GITHUB_TOKEN %>"
// },
// "auth": {
// "enabled": true,
// "mode": "all",
// "verifiers": {
// "jwt": {
// "secret": "<% VIEWER_JWT_SECRET %>",
// "issuer": "https://login.example.com/",
// "audience": "xopat-viewer",
// "forward": false, // strip viewer JWT before upstream call
// "userClaimHeader": "x-user-sub"
// }
// }
// }
//}
},
//The server supports direct server-side execuion, configure your optional auth here
"rpcAuth": {
//Default system login
"default": {
//by default no auth
}
// //Custom HTTP Client context auth accepted by server, see above
//"my-service-context": {
// "enabled": true,
// "mode": "all",
// "verifiers": {
// "jwt": {
// "secret": "<% YOU_CAN_READ_ENV_OR_ADD_STATIC_VALUE %>",
// "issuer": "https://login.example.com/",
// "audience": "xopat-viewer",
// "forward": false,
// "userClaimHeader": "x-user-sub"
// }
//}
},
// Server side configurations for your elements are available here, these are not dynamically changeable,
// never exposed to client. Check README of your plugin or module to see the syntax.
//
// These blocks are also the **second source** consulted by an
// element's `requiredConfig` declaration in include.json when
// `client.<env>.pluginSelectionMode` is "available": a path like
// `server.secure.<plugins|modules>.<id>.foo.bar` carries equal
// weight to the public `<plugins|modules>.<id>.foo.bar` block.
// The plugin author lists *what* keys must be configured; this
// is the right home for whichever of those keys are sensitive
// (API key bindings, proxy aliases referencing a secret, etc.).
"modules": {
////custom values here
//"my-module-id": {
//
//}
},
"plugins": {
//similar to modules
}
}
},
/**
* Below are project-specific paths used internally. Do not modify if you don't know what you are doing.
*/
"monaco": "src/libs/monaco/",
"openSeadragonPrefix": "src/libs/",
"openSeadragon": "openseadragon.js",
"openSeadragonConfiguration": {
"showNavigator": true,
"maxZoomPixelRatio": 2,
"zoomPerClick": 2,
"zoomPerScroll": 1.7,
"blendTime": 0,
// This is due to annotations (multipolygon brush) that are disabled during animations
// ease out behavior makes user think they can already start drawing and slows them down
"animationTime": 0,
"showNavigationControl": false,
"crossOriginPolicy": "Anonymous"
},
/**
* JS Source files. Each group conforms to pre-determined folder path.
*/
"js": {
// src/libs key: source / [sources,list]
"libs": {
"jquery": "jquery.min.js",
"i18n": ["i18next.jquery.min.js", "i18next.min.js"],
"kinetic": "kinetic-v5.1.0.min.js",
"scroll_to": "scrollTo.min.js",
"unzip_it": "unzipit.min.js",
"ajv": "ajv7.min.js",
"render": "flex-renderer/flex-renderer.js"
},
// src/external key: source / [sources,list]
"external": {
"protocols": [
"dziexttilesource.js",
"emptytilesource.js",
"previewsource.js"
],
"common": [
"enjoyhint.js",
"js.cookie.js",
"osd_tools.js",
"scalebar.js",
"nouislider.min.js",
"autocomplete.js"
]
},
/**
* Unlike other keys, keys inside 'src' are pre-determined and must be kept:
* "env" sets up the browser environment - styles
* "loader" is the core component module functionality, loaded as soon as possible.
* "deps" are UI dependencies, loaded before JS index code.
* "app" contains the core files, loaded after JS index code.
*
* key: source / [sources,list]
*/
"src": {
//"env": "",
"loader": ["dist/store.js", "dist/loader.js"],
"deps": [],
"app": [
"dist/classes/user.js",
"parse-input.js",
// Patches OpenSeadragon.TileSource.prototype.downloadTileStart and
// OpenSeadragon.makeAjaxRequest to route through xOpat's HttpClient
// (proxy alias + CSRF + JWT) when a TileSource carries
// `__xopatHttpClient` (stamped by the slide-protocol registry).
// Must load AFTER the OSD library and BEFORE dist/app.js so the
// patches are installed before any TileSource is opened.
"dist/tile-source.js",
"dist/app.js",
"user-interface.js",
"layers.js",
]
},
"ui": {
"van": ["index.js"]
}
},
/**
* Css files shadow the JS structure, with custom keys except for "src"
*/
"css": {
"libs": {
"primer": "primer_css.css",
"fontawesome": "fontawesome/css/v6-all.css",
"phosphor": "phoshor-icons/style.css",
"fa-to-phosphor": "phoshor-icons/fa-overrides.css",
"tailwind": "tailwind.min.css"
},
"external": {
"enjoyhint": "enjoyhint.css",
"nouislider": "nouislider.css"
},
"src": {
"env": ["assets/style.css", "assets/custom.css"]
}
}
}