Hub Utilities
Hub provides several utility classes in Utils/ for environment management, worker threads, PDF generation, notifications, and more.
EnvironmentHelper
Utils/EnvironmentHelper.ts — Singleton connector that manages application configuration, runtime state, and PDF printing.
Key Responsibilities
| Area | Methods | Purpose |
|---|---|---|
| App Settings | getAppSettings(), SyncAppSettings(), seedAppSettings() | Read/write the AppSettings singleton (fixed _id, see Database Models). Syncs version, build timestamp, and feature flags. Solution projects override the protected seedAppSettings($settings) hook to fill their own defaults from the configuration when the document is created for the first time, instead of overriding getAppSettings() |
| Configuration | SyncConfigsData(), ResetConfigsCache() | Synchronizes JSONP configuration files with ConfigEntry DB storage; drops the runtime cache of the parsed configurations |
| PDF Printing | InitPDFPrint(), PrintPDF() | Initialize Puppeteer browser, render URLs/HTML to PDF |
| Event Loop | getEventLoopState() | Returns event loop health metrics |
| Release Notes | getReleaseNotes(), getWhatsNew() | Load release notes and "what's new" content from JSONP files |
| FAQ | getFAQ() | Load FAQ content from JSONP configuration |
| Feedback | Feedback() | Submit user feedback via MailEngine |
| Runtime | getEnvironmentInfo() | Server environment details (Node version, OS, memory, uptime) |
RuntimeHandler Symbol
EnvironmentHelper is registered as the *.RuntimeHandler symbol in the connectors register, making it accessible via the standard RuntimeHandler connector symbol from any project.
Configuration Cache
Every configuration registered in getConfigsSource() (release notes, FAQ, cookie bar, legal documents) is read from ConfigEntry and parsed once, then kept in a cache shared by the whole runtime. That matters because the same helper is reached through two different objects: HTTP resolvers, cron tasks and mails use the singleton from Loader.getInstance().getEnvironmentHelper(), while every LCP call runs on the connector instance the register keeps per auth token, one per session.
| Fact | Consequence |
|---|---|
| A configuration deployed while the application runs is not picked up on its own | Press Reset configs cache in the dashboard Registry tab, or restart the application. The method returns the number of dropped configurations, which the button reports in a toast |
| The cache is shared by all readers | One reset covers the SPA of every logged-in session, the standalone pages and the PDF exports at once |
| Cached DAO objects are handed out by reference | Treat them as read-only — mutating one corrupts the configuration for the whole runtime |
| The cache lives per V8 isolate | A worker thread keeps its own copy, so a job that reads configurations must stay on the main thread |
| Configuration reads are deliberately identity-free | A requester-scoped read must not use this cache — the content is cached per configuration type only |
Threads
Utils/Threads.ts — Worker thread management using Node.js worker_threads.
Static Methods
| Method | Purpose |
|---|---|
IsMainThread() | Check if running in the main thread |
OnMessage($callback) | Register message handler in worker thread |
Send($data) | Send message from worker to parent |
getData() | Get workerData passed during thread creation |
Sleep($time) | Async sleep utility (default 1000ms) |
Instance Methods
const thread = new Threads();
thread.Create({
binClone : true, // clone bin/ directory for worker
initData : { isCron: true }, // workerData passed to thread
scriptPath: "" // custom entry script (default: same as main)
});
thread.OnMessage(($data) => { /* handle response */ });
thread.Send("message to worker");
Hub Usage
The Loader creates a cron worker thread during onDbPrepared() (if authManagerWorker.enabled). This thread runs:
- Activation check — Periodic user account expiration check (
activationCheck.interval) - Cleanup service — Expired reset token cleanup (
cleanUpService.interval)
PuppeteerHandler
Utils/PuppeteerHandler.ts — Headless Chrome/Chromium controller for PDF generation and screenshots.
Key Methods
| Method | Purpose |
|---|---|
Export($input, $options?) | Render URL or HTML to PDF/screenshot |
setConfig($value) | Override Puppeteer configuration at runtime |
Export Options
await handler.Export({
url : "https://example.com/report", // URL to render (or use html)
html : "<html>...</html>", // Direct HTML content
format : "pdf", // "pdf" or "screenshot"
cookies: [], // Inject cookies for auth
verbose: true // Log progress
});
Configuration
puppeteer: {
enabled : true,
urlThreads : 2, // concurrent browser pages
maxWaitTime : 30000, // max render wait (ms)
proxy : { enabled: false, location: "" },
chromeBuildId: "", // specific Chrome version
cacheDir : "" // Chrome binary cache directory
}
Requires puppeteer-core and oidis/oidis-chromium-base packages.
PushNotifications
Utils/PushNotifications.ts — In-memory broadcast of live events to every open GUI connection (no external service).
Created in the Loader constructor (server-side only) and reached through Loader.getInstance().PushNotifications().
Push({type, data})calls every registered listener; there is no targeting (by user, group or organization) and nothing is stored — a client that is not connected at that moment never receives the event. Only the lastHEADER_CHANGE/HEADER_RESTOREevent is replayed to a newly attached listener.- The GUI attaches through
EnvironmentConnector.AttachToPushNotifications()(a persistent connection opened byBasePageLayoutController) and handles events in the overridableprotected async pushNotificationHandler($event); the base implementation only logs unknown types, so an override callssuperfor types it does not handle. - Every connection receives every event, including anonymous pages — never put private data (not even organization
ids) into
data. Send a bare signal (a kind) and let each page load its own details through an authorized connector call.
// Backend
(<any>Loader.getInstance()).PushNotifications?.()?.Push({type: "my.app.attention", data: {kind: "pairing"}});
// Page controller
protected async pushNotificationHandler($event : IPushNotificationEvent) : Promise<void> {
if ($event?.type !== "my.app.attention") {
await super.pushNotificationHandler($event);
return;
}
// check the rights of the signed-in user, then load the details through an authorized connector call
}
AuthManager (Coordinator)
Utils/AuthManager.ts — The central authentication coordinator. Composed from 11+ partial classes via @Partial. See Authentication for full documentation.
Other Utilities
| Class | File | Purpose |
|---|---|---|
ConfigurationsManager | Utils/ConfigurationsManager.ts | JSONP configuration loading and dynamic updates |
SendMail | Utils/SendMail.ts | SMTP transport wrapper (nodemailer) used by MailEngine |
Convert | Utils/Convert.ts | Hub-specific type conversions |
AdminInitHelper | Utils/AuthManager.ts | First-time admin initialization flow |
See also: Authentication | Hub Backend Overview | Hub Configuration