Source: config.json

/**
 * @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"]
        }
    }
}