@novahelm/core
v2026.6.2
Published
NovaHelm core — service registry, types, errors, events, and shared utilities.
Downloads
1,972
Maintainers
Readme
@novahelm/core
Foundation package for NovaHelm -- provides the singleton service registry, typed event system, structured errors, module definitions, and shared utilities used by every other @novahelm/* package.
Quick Start
pnpm add @novahelm/coreimport { initNova, getDb, getRedis, getAuth } from "@novahelm/core";
// 1. Create service instances using their respective factory functions
import { createDb } from "@novahelm/db";
import { createAuth } from "@novahelm/auth";
const db = createDb({ databaseUrl: env.DATABASE_URL });
const auth = createAuth({ /* ... */ });
// 2. Register all services once at app startup
initNova({ db, redis, auth, storage, email, logger, config });
// 3. Any package retrieves services from the registry at runtime
const db = getDb<NovaDb>();
const redis = getRedis<Redis>();Registry
The registry is the central coordination point. Consumer apps call initNova() once at startup, then any @novahelm/* package retrieves services via typed getters -- no direct cross-package imports needed.
import {
initNova,
isInitialized,
getDb,
getRedis,
getAuth,
getStorage,
getEmail,
getLogger,
getConfig,
resetRegistry,
} from "@novahelm/core";| Function | Description |
|----------|-------------|
| initNova(services) | Register all service instances. Call once at startup. |
| isInitialized() | Check if the registry has been initialized |
| getDb<T>() | Get the database instance (see @novahelm/db + @novahelm/engine) |
| getRedis<T>() | Get the Redis/Valkey instance |
| getAuth<T>() | Get the NovaAuth instance (see @novahelm/auth) |
| getStorage<T>() | Get the S3/MinIO storage instance |
| getEmail<T>() | Get the email provider instance |
| getLogger<T>() | Get the Pino logger instance |
| getConfig<T>() | Get the NovaConfig from novahelm.config.ts |
| resetRegistry() | Reset registry state (testing only) |
Typed Registry
For stricter typing without manual generics, use the typed registry getters:
import { getTypedDb, getTypedRedis, getTypedAuth } from "@novahelm/core";
const db = getTypedDb(); // MinimalDb interface
const redis = getTypedRedis(); // MinimalRedis interfaceProject Resolver (Platform Mode)
In multi-tenant platform mode, setProjectResolver() enables project-scoped service resolution via AsyncLocalStorage:
import { setProjectResolver, clearProjectResolver } from "@novahelm/core";
setProjectResolver((name) => {
// Return project-scoped service based on AsyncLocalStorage context
return projectContext.get(name);
});Error System
Structured errors with automatic HTTP status code mapping. The @novahelm/api package bridges these to TRPCError codes automatically.
import { NovaError, isNovaError, getHttpStatus, ERROR_MAP } from "@novahelm/core";
// Throw a typed error
throw new NovaError("NOT_FOUND", "User not found");
throw new NovaError("FORBIDDEN", "Upgrade required", { planRequired: "pro" });
// Handle errors
if (isNovaError(error)) {
const status = getHttpStatus(error); // 404
console.log(error.forgeCode); // "NOT_FOUND"
console.log(error.httpCode); // "NOT_FOUND"
}| Error Code | HTTP Status | Description |
|------------|-------------|-------------|
| NOT_FOUND | 404 | Resource not found |
| UNAUTHORIZED | 401 | Not authenticated |
| FORBIDDEN | 403 | Insufficient permissions |
| BAD_REQUEST | 400 | Invalid input |
| CONFLICT | 409 | Resource conflict |
| INTERNAL_ERROR | 500 | Server error |
| RATE_LIMITED | 429 | Too many requests |
| PLAN_REQUIRED | 403 | Feature requires plan upgrade |
| LIMIT_EXCEEDED | 403 | Usage limit exceeded |
| UPLOAD_TOO_LARGE | 413 | File exceeds size limit |
| MODULE_DISABLED | 412 | Module not enabled |
Event System
Typed event emitter for cross-package communication. Events are emitted asynchronously (fire-and-forget via setImmediate).
import { getEmitter, emitNovaEvent } from "@novahelm/core";
// Listen for events
const emitter = getEmitter();
emitter.on("user:created", (user) => {
console.log(`New user: ${user.email}`);
});
emitter.on("order:created", (order) => {
// Trigger fulfillment...
});
// Emit events (fire-and-forget, non-blocking)
emitNovaEvent("post:published", post);Event categories: auth:*, user:*, tenant:*, subscription:*, payment:*, order:*, cart:*, media:*, post:*, ai:*, notification:*, feedback:*, flag:*, audit:*
Hooks
Consumer apps can register lifecycle hooks that wire into the event emitter:
import { defineHooks } from "@novahelm/core";
const hooks = defineHooks({
"user:created": async (user) => {
await sendWelcomeEmail(user);
},
"order:confirmed": async (order) => {
await notifyWarehouse(order);
},
});
// Pass hooks to initNova
initNova({ db, redis, auth, logger, config, hooks });Module System
Define standalone modules that extend the platform via typed extension points:
import { defineModule } from "@novahelm/core";
import type { ModuleManifest } from "@novahelm/core";
export default defineModule({
slug: "my-module",
name: "My Module",
description: "Custom functionality",
version: "1.0.0",
category: "productivity",
status: "stable",
routers: [/* NovaRPC endpoint groups */],
navItems: [/* sidebar nav entries */],
schema: [/* defineModel() declarations */],
workers: [/* BullMQ worker definitions */],
events: [/* event subscriptions */],
collections: [/* admin-kit collections */],
pages: [/* dashboard page components */],
});Utilities
Common helpers re-exported for convenience (also available via @novahelm/core/utils):
import {
// IDs
createId, prefixedId, shortId,
// Strings
slugify, truncate, capitalize, initials, escapeHtml, stripHtml, excerpt,
// Formatting
formatCurrency, formatBytes, formatNumber, timeAgo, formatDate,
// URLs
buildUrl, isAbsoluteUrl, joinPath,
// Objects & Arrays
pick, omit, deepMerge, chunk, unique, groupBy, compact,
// Validation
isEmail, isUrl, isUuid, isEmpty,
// Time
sleep, retry, isExpired,
// Hashing
stableHash, sha256,
// Tailwind
cn,
} from "@novahelm/core";API Reference
| Export | Description |
|--------|-------------|
| CORE_VERSION | Current package version (CalVer) |
| initNova(services) | Initialize the service registry |
| isInitialized() | Check registry status |
| getDb<T>() / getRedis<T>() / getAuth<T>() | Service getters |
| getStorage<T>() / getEmail<T>() / getLogger<T>() | Optional service getters |
| getConfig<T>() | Config getter |
| resetRegistry() | Reset (testing only) |
| setProjectResolver(fn) / clearProjectResolver() | Platform-mode project scoping |
| NovaError | Structured error class |
| ERROR_MAP | Error code to HTTP code mapping |
| getHttpStatus(error) | Get numeric HTTP status from error |
| isNovaError(error) | Type guard |
| NovaEventEmitter | Typed event emitter class |
| getEmitter() | Get singleton emitter |
| emitNovaEvent(event, ...args) | Fire-and-forget event emission |
| defineHooks(map) / registerHooks(hooks) | Lifecycle hook system |
| defineModule(manifest) | Define a module manifest |
| notify(options) | Send a notification |
| evaluateConfigValue(condition, context) | Remote config evaluation |
| getVariant(experiment, userId) | A/B experiment variant assignment |
| defineSyncShape(shape) | Define offline sync shape |
| cn(...classes) | Tailwind class merge utility |
