Qlik Engine gateway and Node SDK with pooled sessions, caching, and enigma-style proxies.
A Qlik Engine gateway that pools sessions and provides an enigma-compatible Node SDK.
- One Engine session per userId + appId, shared across callers (in-flight open de-dupe).
- Caches common app objects (objects, fields, variables, measures) to reduce duplicate calls.
- Broadcasts changed (optional layout) and synthetic loading events to all subscribers.
- Node client SDK that exposes enigma-style proxies.
``bash`
npm install
npm run build
npm start
Defaults:
- HTTP: http://localhost:1337GET /health
- Health:
dotenv-flow loads .env*. startServer options override env.
| Setting | Default | Env | Programmatic |
| --- | --- | --- | --- |
| HTTP port | 1337 | PORT | startServer({ port }) |120000
| Session idle (ms) | | SESSION_IDLE_MS | startServer({ sessionIdleMs }) |125
| Changed debounce (ms) | | CHANGED_DEBOUNCE_MS | startServer({ changedDebounceMs }) |startServer({ getEnigmaConfig })
| Qlik config provider | - | - | |cloud
| Qlik connection mode | | QLIK_CONNECTION_MODE | getEnigmaConfig().connectionMode |QLIK_TENANT
| Qlik tenant (cloud) | - | | getEnigmaConfig().qlikTenant |QLIK_ENGINE_URL
| Qlik engine URL (certs) | - | | getEnigmaConfig().qlikEngineUrl |QLIK_CERTIFICATES_PATH
| Certificates path (certs) | - | | getEnigmaConfig().certificatesPath |startServer({ getEnigmaSession })
| Custom session factory | - | - | |startServer({ getResponseInterceptors })
| Response interceptors | - | - | |startServer({ onError })
| Error handler | - | - | |console.log
| Logger | | - | startServer({ logger }) |
Notes:
- In cloud mode, clients must provide a Qlik API token (see Client).certificates
- In mode, clients must provide a Qlik user directory.getEnigmaConfig
- Providing bypasses env-based config for Qlik connection settings.logger: null
- disables logs.
- Sessions are keyed by userId + appId; idle cleanup uses sessionIdleMs.NOT_CONNECTED
- If a session is closed or returns , the gateway marks it dead and rehydrates on the next call or subscription.GET /health
- includes sessionDetails with per-session status (dead/alive, idle time, handles, subscriptions).changed
- can optionally include a layout (see includeLayout in Client options).loading
- Synthetic helps UI state around longer-running calls.createSessionObject
- is cached only when qInfo.qId is provided; cache is per session and cleared by destroySessionObject.
- Alive session: enigma session is open; handles point to live APIs; calls go through normally.
- Dead session: enigma session closed or a call returned NOT_CONNECTED; handles are kept but their APIs are cleared.SESSION_CLOSED
- Rehydrate: on the next call/subscribe, the gateway opens a new enigma session, recreates global/app, and rebinds known handles (objects/fields/variables/measures). Unknown handles throw .sessionIdleMs
- Idle cleanup: a session is disposed only when it has no subscriptions and has been idle longer than (same rule for alive and dead).
`ts
import { QlikGatewayClient } from 'claviz-liminal-qlik/client';
const session = await QlikGatewayClient.connectSession('http://localhost:1337', {
userId: 'user@example.com',
appId: 'YOUR_APP_ID',
token: process.env.QLIK_API_TOKEN,
userDirectory: 'YOUR_USER_DIRECTORY', // certificates mode
});
const app = await (await session.open()).openDoc();
const viz = await app.getObject('YOUR_OBJECT_ID');
viz.on('changed', ({ layout }) => {
// layout is pushed by the server when includeLayout is true
}, { includeLayout: true });
viz.on('loading', ({ active }) => {
// show/hide overlay
});
await session.close();
`
- QlikGatewayClient.connect(url, { timeoutMs?, token?, userDirectory? }) (default timeoutMs is 30000).QlikGatewayClient.connectSession(url, { userId, appId, timeoutMs?, token?, userDirectory? })
- .openGlobal/openApp
- params: { userId, appId, token?, userDirectory? } (token used for Qlik Cloud).{ includeLayout?, debounceMs? }
- Subscription options: for changed.EnigmaGatewaySession.close()` only disconnects the socket if it owns it.
-