fuse-core-express
v1.1.0
Published
FuseCore Express Encrypted Package
Downloads
314
Readme
FuseCore — Express.js Development Toolkit
FuseCore (fuse-core-express) is a batteries-included toolkit for building production Express.js apps. It bundles the cross-cutting concerns you would otherwise wire up by hand — caching, structured logging, a backend HTTP/ajax client, manifest-driven service discovery, runtime monitoring, and request utilities — behind one small, consistent API.
✨ What you get
- Cache — one async
get/setAPI over an in-memory backend or Redis (TTL, never-expire, plus Redis extras likeexists/expire/ttl/keys). - Log — rotating, auto-zipping file logger with level control; can take over
console. - Ajax — a robust backend HTTP client with timeouts, slow-request logging, request/response content-type handling,
requestAllfan-out, and a streamingproxy. - Manifest — manifest-driven config and backend URL resolution (
manifest.get,manifest.getBackendUrl). - Monitor — built-in memory/CPU/404/5xx monitoring with an HTTP endpoint for dashboards.
- Request utilities — user-agent and language parsing (
getUAInfo,getLangInfo) plus a request filter that fixesreq.ipbehind a proxy and addsreq.realUrl.
This package is the encrypted distribution. It exposes exactly the same runtime API as the regular build, with one extra bootstrap step (decryption) before
init— see the Quick Start. Once decrypted in memory at startup, everything behaves identically to the public source. It is MIT-licensed and public — see Why an encrypted build? at the end.
📚 Documentation
The encrypted package ships the same documentation tree as the regular package, at the package root under docs/:
- 📚 Docs index —
docs/README.md - 📖 Per-module API reference —
docs/api/{lifecycle,cache,log,request,manifest,monitor,ajax}.md - 🌐 OpenAPI 3.1 spec for the Monitor HTTP endpoints —
docs/openapi/fusecore-monitor.yaml
Once the package is installed under node_modules/fuse-core-express/, the docs are available offline at node_modules/fuse-core-express/docs/.
🚀 Quick Start
The encrypted build adds exactly one step over the regular build: decrypt the bundle (stage 1) before initializing (stage 2). initDecryption must be called once, and resolve, before init or any other FuseCore access.
import FuseCore from 'fuse-core-express';
import path from 'path';
import { createRequire } from 'module';
import { fileURLToPath } from 'url';
const __dirname = path.dirname(fileURLToPath(import.meta.url));
const require = createRequire(import.meta.url);
const version = require('fuse-core-express/package.json').version;
// Stage 1 — decrypt the bundled source.
// `recipient-keys-<version>.json` ships inside this package under `keys/`.
// Pass the absolute path to the key file matching the installed version.
const privateKeyPath = path.join(
__dirname,
`node_modules/fuse-core-express/keys/recipient-keys-${version}.json`
);
await FuseCore.initDecryption(privateKeyPath);
// Stage 2 — initialize FuseCore (identical to the regular build).
await FuseCore.init({
common: { listenPort: 3000 },
cache: { impl: 'memory' },
log: { path: './logs', level: 'info' },
monitor: { mem: true, cpu: true, req404: true, req5xx: true }
});
// ...your app code here — everything below works exactly like the regular build...
await FuseCore.cache.set('greeting', 'hello', 60);
FuseCore.logger.info('FuseCore ready');
await FuseCore.shutdown();After
initDecryptionresolves, the bootstrap proxies every access (FuseCore.cache,FuseCore.logger,FuseCore.ajax, …) to the decrypted modules, so the rest of your code is identical to the regular package. The decryption-specific API is documented in Decryption Reference below.
⚙️ Configuration
FuseCore.init(options) takes a single merged config object. Every section is optional; sensible defaults apply. See docs/api/lifecycle.md for the authoritative full schema.
await FuseCore.init({
common: {
expressApp: null, // your Express app instance (enables request filter & monitor)
listenHostname: '', // hostname/ip the HTTP server listens on
listenPort: 3000, // port the HTTP server listens on
},
cache: {
impl: 'memory', // 'memory' (default) or 'redis'
redis: {
url: 'redis://localhost:6379',
enableTls: false,
clientOptions: {} // password, database, etc.
}
},
log: {
path: '', // directory for log files
level: 'info', // minimum level written to file
takeOverConsole: false, // pipe console.* into the log files
extraOutputStreams: { // extra writable streams per level
info: process.stdout,
error: process.stderr,
},
},
ajax: {
timeout: 10000, // default request timeout (ms)
slowThreshold: 3000, // requests slower than this are slow-logged (ms)
defaultHeaders: { 'X-Requested-With': 'FuseCore Web component V1.0' },
agentOptions: {} // passed to the http/https agent
},
manifest: {
path: '', // directory containing the manifest file
name: '', // manifest name to load
},
monitor: {
prefix: '', suffix: '', // prefix/suffix for all monitor keys
mem: true, cpu: true, // auto-monitor memory / cpu
req404: true, req5xx: true, // monitor 404 / 5xx responses
},
isPrimaryProcess: true // in cluster mode, whether this is the primary
});Key fields:
common.expressApp— your Expressapp; required for the request filter and monitor HTTP endpoint.cache.impl—'memory'(default) or'redis';cache.redis.*configures the Redis connection.log.path/log.level— log directory and minimum file level;takeOverConsoleredirectsconsole.*into the logs.ajax.timeout/ajax.slowThreshold— default backend timeout and slow-log threshold in ms.manifest.path/manifest.name— where to find and which manifest to load for backend resolution.monitor.mem|cpu|req404|req5xx— toggles for the built-in monitors;isPrimaryProcessadjusts behavior in cluster workers.
🧩 Functional APIs
Concise highlights below; each links to its full reference under docs/api/.
Cache — docs/api/cache.md
Async get/set over memory or Redis. TTL is in seconds; a negative/zero TTL means never-expire (per backend); setting null deletes the key.
const cache = FuseCore.cache;
await cache.set('user:123', { name: 'John', age: 30 }, 3600); // expires in 1h
const user = await cache.get('user:123'); // { name: 'John', age: 30 }
await cache.set('user:123', null); // delete key
// Redis backend adds: exists, expire, ttl, keys, flushAll
const exists = await cache.exists('user:123');
const keys = await cache.keys('user:*');📖 Full reference: docs/api/cache.md
Log — docs/api/log.md
A rotating, auto-zipping logger. Methods are safe to call before init, but only flush once init finishes.
FuseCore.logger.info('server started', { port: 3000 });
FuseCore.logger.error('backend failed', err);
const logger = FuseCore.getLogger('orders'); // named logger📖 Full reference: docs/api/log.md
Ajax — docs/api/ajax.md
A backend HTTP client driven by manifest server codes, with timeouts, slow logging, and a uniform response envelope ({ ok, status, data, raw, headers, duration, ... }).
// Single request
const res = await FuseCore.ajax.request({
server: 'property', // server code defined in the manifest
version: 'v4.6',
path: '/nearby',
method: 'POST',
isWeb: true,
req, // forwards relevant headers/IP from the incoming request
});
if (res.ok) render(res.data);
// Streaming proxy (pipes req/res through to the backend)
await FuseCore.ajax.proxy({ server: 'property', path, method: 'POST', req, res });
// Parallel fan-out — always resolves; check each result's .ok
const [property, news] = await FuseCore.ajax.requestAll([
{ server: 'property', version: 'v4.6', path: '/nearby' },
{ server: 'news', version: 'v4.8', path: '/news' },
]);📖 Full reference: docs/api/ajax.md
Manifest — docs/api/manifest.md
Read manifest values by dotted path and resolve backend URLs.
const manifest = FuseCore.manifest;
const value = manifest.get('prop1.prop2.prop3');
const url = manifest.getBackendUrl('property', '/nearby', 'v4.6');📖 Full reference: docs/api/manifest.md
Monitor — docs/api/monitor.md
Records counters/values and auto-monitors memory, CPU, 404s, and 5xx. Exposes an HTTP endpoint for dashboards (contract in docs/openapi/fusecore-monitor.yaml).
FuseCore.monitor.recordCnt('order_created_Count', '/orders');
FuseCore.monitor.recordVal('order_amount_Value', '/orders', order.amount);
const summary = FuseCore.monitor.getCurrentSummary('/'); // string[] of metric lines📖 Full reference: docs/api/monitor.md · 🌐 HTTP endpoint contract
Request utilities — docs/api/request.md
Parse user-agent and language from an Express request; the auto-registered filter fixes req.ip behind a proxy and adds req.realUrl.
const ua = FuseCore.request.getUAInfo(req); // { isMobile, platform, browser, ... }
const lang = FuseCore.request.getLangInfo(req); // { primaryLanguage, isEnglish, lang, ... }📖 Full reference: docs/api/request.md
🔐 Decryption Reference
Everything below is specific to the encrypted build. If you only need to use FuseCore, the Quick Start is enough — read on for the full decryption API, key handling, and troubleshooting.
FuseCore.initDecryption(privateKeyPath, payloadPath?) → Promise<FuseCore>
Decrypt the bundled source. Must be called once before FuseCore.init or any other module access.
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
| privateKeyPath | string | — | Required. Absolute path to the recipient private key JSON file shipped under this package's keys/ directory. |
| payloadPath | string | <package>/secure-package.vxz | Optional override for the encrypted payload location. Useful only if you have relocated the .vxz file. |
Returns
The FuseCore instance, for chaining.
Throws
| Error | Cause |
|---|---|
| Private key path is required for encrypted FuseCore | privateKeyPath is falsy. |
| Private key not found: <path> | The file at privateKeyPath does not exist. |
| Signature verification failed | The bundle's signature does not verify against the bundled signer public key. The package may be tampered with or the keys do not match. |
| Key files not found in either ./keys/ or ../keys/ directories | The signer public key file (signer-keys-<version>.json) is missing from the package. |
Examples
Using the bundled key file (development/testing):
const privateKeyPath = path.join(
__dirname,
`node_modules/fuse-core-express/keys/recipient-keys-${version}.json`
);
await FuseCore.initDecryption(privateKeyPath);Using a custom key file location (production):
await FuseCore.initDecryption('/etc/secrets/fusecore-recipient-key.json');Key Management
Method 1 — Bundled keys (suitable for development/testing)
The published package includes the matching recipient key files under keys/:
node_modules/fuse-core-express/keys/
├── build-version.json
├── recipient-keys-<version>.json ← contains recipient private key (used here)
├── signer-keys-<version>.json ← signer public key (used by the decryptor)
└── README.mdPoint initDecryption at the recipient key file matching the installed version.
Method 2 — Custom key file path (production)
Move the recipient private key out of the package to a secret-store location (mounted secret, KMS-fetched file, etc.) and point initDecryption at its absolute path:
await FuseCore.initDecryption('/etc/secrets/fusecore-recipient-key.json');Restrict filesystem permissions on the key file so only the process user can read it.
Package File Structure
node_modules/fuse-core-express/
├── index.js # Entry point — installs the decryption proxy.
├── secure-package.vxz # Encrypted, signed, gzipped source bundle.
├── decryptor.js # Standalone decryptor (used internally).
├── docs/ # Same docs/ tree as the regular build.
│ ├── README.md
│ ├── api/*.md
│ └── openapi/fusecore-monitor.yaml
├── keys/
│ ├── build-version.json
│ ├── recipient-keys-<version>.json
│ ├── signer-keys-<version>.json
│ └── README.md
└── package.json⚠️ Security Notes
- The encrypted build is not access control. The source is public on GitHub under MIT. The encryption + signature exist to (a) prevent downstream tooling from drawing incorrect conclusions from minified/transformed JavaScript and (b) provide integrity (every bundle is signed; tampering breaks decryption).
- Do not commit the bundled recipient private key into your application repository. For production, prefer Method 2 (custom path) and mount the key file from a secret manager.
- The signer private key never ships with the package. It lives only in the build environment and is required to (re-)produce a valid bundle.
🛠️ Troubleshooting
FuseCore not decrypted. Call initDecryption(privateKeyPath) first.
Some FuseCore API was accessed before initDecryption resolved. Ensure await FuseCore.initDecryption(...) runs before any other FuseCore call, including init.
Private key not found: <path>
The path passed to initDecryption does not exist. Verify:
- The path is absolute (or relative to a
__dirnameyou control). - The version suffix on the key filename matches the installed package version (
require('fuse-core-express/package.json').version).
Signature verification failed
The decryptor verified the bundle against the bundled signer public key and the signature did not match. Likely causes:
- The recipient key file does not match the bundle's build version. Reinstall the package or use the matching key version.
- The
secure-package.vxzwas modified after build.
Key files not found in either ./keys/ or ../keys/ directories
The decryptor expected to find signer-keys-<version>.json in the package's keys/ directory. If you relocated the package or pruned files, restore the original keys/ layout.
💡 Why an encrypted build?
This package is public and MIT-licensed — the source on GitHub is the source of truth. The encrypted build is not an access-control or secrecy mechanism. It exists so that downstream tooling — including LLM-based code assistants that scan node_modules — does not draw incorrect conclusions about behavior from minified or machine-transformed JavaScript. The signature additionally provides integrity: every bundle is signed, and tampering breaks decryption. To understand how FuseCore works, read the source and the API reference, not the bundled output.
🔗 Related
- Main project on GitHub: https://github.com/ds3783/FuseCoreExpress
- Build-time documentation (for maintainers): the
secure-buildcapability spec (openspec/specs/secure-build/spec.md) in the source repository.
Encryption algorithm: AES-256-GCM + RSA-OAEP (key wrap) + RSA-PSS-SHA256 (signature)
