All source files live in src/ and are written in TypeScript. Each entry-point module is compiled by esbuild into a single self-contained .js file in dist/. Shared modules (types, config, permissions, mvs-builder) are not separate output files — they are bundled into whichever entry points import them.
Shared Modules#
src/types.ts#
Defines all shared TypeScript interfaces and the inter-context message protocol. This is the single source of truth for data shapes across the entire codebase.
Key exports:
RepType— union type of all valid Mol* representation strings ("cartoon","ball_and_stick", etc.)RuleRepType— extendsRepTypewith|"highlight"for custom rulesTargetDefinition— shape of one entry inAppConfig.targetsCustomRule— full data model for a user-defined visual ruleExtensionSettings— the master settings object stored inchrome.storage.syncPreset— shape of a named templateOpenViewerMessage— message sent from content script to backgroundInitMolstarMessage— message sent from viewer to sandbox iframeSandboxReadyMessage— message sent from sandbox to viewer on load
src/config.ts#
Contains the static AppConfig object. The authoritative registry for everything the extension knows about molecular components and visual representations.
Key exports:
AppConfig.RepSchema— maps representation keys to their labels and configurable sub-parametersAppConfig.targets— array ofTargetDefinitionobjects (protein, nucleic, ligand, carbs, lipid, ion, water, all)AppConfig.presets— named built-in templatesAppConfig.getDefaults()— generates a completeExtensionSettingsobject from the targets array with fallback values; used everywhere storage settings are read
src/permissions.ts#
Manages dynamic host permission requests for custom domains. Cross-browser compatible (Chrome MV3 / Firefox MV2).
Key exports:
PermissionsManager.cleanDomain(url)— extracts the hostname from a URL stringPermissionsManager.requestAndRegister(url)— requests host permission, registers the content script, and persists the domain to storage. Must be called directly inside a user-gesture handler (Firefox requirement).PermissionsManager.revokeAndUnregister(url)— removes the permission, unregisters the script, and removes the domain from storage.
src/mvs-builder.ts#
Translates extension settings into a MolViewSpec JSON tree. All user-controlled values are sanitized before being embedded.
Key exports:
MvsBuilder._buildBaseTemplate(url, format, settings)— builds the complete MVS JSON object; called by bothsandbox.ts(rendering) andcreateViewerUrl(sharing)MvsBuilder.createViewerUrl(url, format, settings)— encodes the MVS tree as amolstar.org/viewer/URL for external sharingMvsBuilder._sanitizeString(value, maxLength)— strips control characters, caps lengthMvsBuilder._sanitizeColor(colorType, colorVal)— validates against theme allowlist or#rrggbbpatternMvsBuilder._sanitizeRepType(repType)— validates againstAppConfig.RepSchemakeysMvsBuilder._deepSanitize(obj, depth)— recursively sanitizes free-form objects (used forcamera_json), caps depth at 2, rejects arrays and prototype-polluting keys
Entry-Point Modules#
src/background.ts → background.js#
The extension service worker (Chrome) / event page (Firefox). Routing and security checkpoint.
Responsibilities:
- Listens for
open_viewermessages from content scripts; validates URL (HTTPS-only) and format before openingviewer.html - Creates the right-click context menu item on install; handles menu clicks with
format=unknownfallback - Listens for
chrome.permissions.onAddedto dynamically register content scripts when new custom domains are authorized
src/content.ts → content.js#
The DOM scanner injected into host webpages. Has no TypeScript imports — compiles to a plain classic script.
Key functions:
getStructureInfo(href, linkElement)— 3-ring scanner: checks the URL, then link text and HTML attributes, then the parent element’s text content. Transforms GitHub blob URLs toraw.githubusercontent.comand GitLab blob URLs to the GitLab API raw endpoint.makeBadge(rawUrl, formatStr, originalHref)— creates the styled<button>badge; blocks click event propagation to prevent SPA navigationinjectMolstarLinker()— main scan pass; skips already-processed links, checks for duplicate badges, marks processed links withdata-ms-processedMutationObserverwith 500 ms debounce handles SPA navigation; disconnects on pageunload
src/viewer.ts → viewer.js#
The privileged shell. Runs inside the extension context with full API access.
Key functions:
isSafeUrl(url)— validates HTTPS protocol and checks hostname against SSRF blocklist (private ranges, loopback, link-local)bootWorkspace(rawUrl, safeFormat)— fetches the file, enforces 25 MB cap, converts to base64 data URI, callsspawnIframespawnIframe(dataUri, format, rawUrl)— reads and filters storage settings using schema allowlist, spawns sandbox iframe, registersSANDBOX_READYlistener, sendsINIT_MOLSTARmessagesetupDragAndDrop()— full-page drag-and-drop overlay for local files
src/sandbox.ts → sandbox.js (bundles mvs-builder.ts)#
The isolated rendering context. Has no access to extension APIs.
Flow:
- Posts
SANDBOX_READYimmediately on script load - On
INIT_MOLSTAR: validates origin (chrome-extension://ormoz-extension://), validates URL (must bedata:ornull), validates format - Converts data URI to a short
blob:URL (anti-lag fix for large files) - Calls
MvsBuilder._buildBaseTemplate()to produce the MVS JSON - Loads via
viewerInstance.loadMvsData()if available, or thePluginExtensions.mvs.loadMVS()fallback
src/popup.ts → popup.js#
The browser toolbar popup. Lightweight — reads storage, applies a selected preset, opens the Studio.
src/options.ts → options.js#
The full Settings Studio. The most complex UI module.
Key functions:
buildUI()— generates per-target accordion cards with representation selectors, color pickers, and sub-parameter drawersaddCustomRuleCard(ruleData?)— creates a full custom rule form card with simple/expert mode toggle and live JSON previewextractCurrentSettings()— reads the entire UI state into anExtensionSettingsobjectinjectSettingsIntoUI(settings)— populates the entire UI from a settings object (used by template loading and JSON import)refreshCustomDomainList()— reads authorized domains from storage and renders the revocation UI- Import validation uses an explicit allowlist (
AppConfig.getDefaults()keys) and capscustomRulesat 50 entries