Skip to main content

TServiceParams

TServiceParams is the single parameter every service function receives. It is built from the dependency graph at wiring time and carries everything the service needs.

export function MyService({ logger, lifecycle, config, scheduler }: TServiceParams) {
// ...
}

Properties​

PropertyTypeDescription
loggerGetLoggerScoped logger, pre-bound to module:service context
lifecycleTLifecycleBaseRegister startup and shutdown callbacks
configTInjectedConfigTyped config object, one namespace per module
schedulerTSchedulerSchedule cron jobs, intervals, and timeouts
eventEventEmitterApp-wide shared event bus
alsAlsExtensionAsync Local Storage — context propagation
contextTContextString identifier for this service: "my_app:service_name"
internalInternalDefinitionUtilities, boot metadata, and internal hooks
paramsTServiceParamsSelf-reference — useful when passing params into a sub-system
my_appGetApis<typeof MY_APP>Other services in your app (after LoadedModules declaration)

logger​

A GetLogger instance pre-bound to this service's context string (my_app:service_name). Every log line is automatically tagged.

logger.info("message");
logger.debug({ key: "value" }, "structured log");
logger.warn({ error }, "something went wrong");

Levels: trace, debug, info, warn, error, fatal, silent.

See Logger for the full API.

lifecycle​

Registers callbacks for lifecycle stages. All methods accept an optional priority number.

lifecycle.onPostConfig(() => { /* config available */ });
lifecycle.onBootstrap(async () => { /* open connections */ });
lifecycle.onReady(() => { /* start serving */ });
lifecycle.onPreShutdown(() => { /* stop accepting work */ });
lifecycle.onShutdownStart(async () => { /* flush and close */ });
lifecycle.onShutdownComplete(() => { /* final cleanup */ });

See Hooks for details on all seven hooks.

config​

The typed config object. Each module's config lives under its own namespace:

config.my_app.PORT // number
config.my_lib.BASE_URL // string
config.boilerplate.LOG_LEVEL // "trace" | "debug" | "info" | ...

Only safe to read after PostConfig. At wiring time, only default values are available.

See Accessing Config.

scheduler​

Schedules work on intervals, cron schedules, or timeouts. All methods return a RemoveCallback.

const stop = scheduler.setInterval(() => doWork(), "30s");
const stopCron = scheduler.cron({ schedule: "0 * * * *", exec: () => hourlyTask() });
// stop() / stop.remove() to cancel

Scheduler jobs do not fire until Ready stage. All registered jobs are automatically stopped at PreShutdown.

See Scheduler.

event​

The app-wide Node.js EventEmitter. The same instance is shared across all services.

event.on("user:created", (user: User) => { ... });
event.emit("user:created", newUser);

The emitter is created fresh at each bootstrap and destroyed at teardown. See Event Bus.

als​

AlsExtension wraps Node.js AsyncLocalStorage. Use it to attach contextual data that propagates through async call chains without passing it explicitly.

als.run({ logs: { correlationId: "abc-123" } }, () => {
// every log emitted from this callback chain includes correlationId automatically
doAsyncWork();
});

// Elsewhere in the call chain:
const store = als.getStore();
const correlationId = store?.logs?.correlationId;

See Async Local Storage.

context​

A branded string identifying this service: "my_app:service_name". Used internally for log tagging and introspection. Can be passed to internal.safeExec to tag error logs.

logger.debug({ context }, "current context");
// context === "my_app:service_name"

internal​

InternalDefinition provides utilities and boot metadata. Mostly useful for framework-level code and advanced service patterns.

internal.utils​

getIntervalMs(offset)​

Converts any TOffset value to a number of milliseconds. Useful when you need the raw ms value for a native API or your own timer logic.

import { MINUTE } from "@digital-alchemy/core";

internal.utils.getIntervalMs("30m") // 1_800_000
internal.utils.getIntervalMs(5 * MINUTE) // 300_000
internal.utils.getIntervalMs([2, "hours"]) // 7_200_000
internal.utils.getIntervalMs({ seconds: 90 }) // 90_000

getIntervalTarget(offset)​

Converts any TOffset to a Dayjs representing now + duration. Useful when you need an absolute target time rather than a relative duration.

const target = internal.utils.getIntervalTarget("5m");
// target is a Dayjs 5 minutes from now

// Example: sleep until a dynamic future time
const next = internal.utils.getIntervalTarget(someOffset);
await sleep(next);

relativeDate(past, future?)​

Human-readable relative time string.

internal.utils.relativeDate(Date.now() - 3 * MINUTE) // "3 minutes ago"
internal.utils.relativeDate(someDate, futureDate) // "in 2 hours"

Other utilities​

Method/PropertyDescription
titleCase(str)Convert snake_case or camelCase to Title Case
object.get(obj, path)Dot-notation read from nested object
object.set(obj, path, value)Dot-notation write into nested object
object.del(obj, path)Dot-notation delete from nested object
object.deepExtend(target, ...src)Deep merge objects
isReference to the is singleton (type guards)

internal.boot​

Introspection into the running application:

internal.boot.loadedModules // Map<name, service APIs>
internal.boot.moduleMappings // Map<name, service functions>
internal.boot.serviceConstructionTimes // [{module, service, duration}]
internal.boot.completedLifecycleEvents // Set<LifecycleStages>
internal.boot.phase // "bootstrap" | "running" | "teardown"
internal.boot.startup // Date when bootstrap began
internal.boot.options // BootstrapOptions passed to bootstrap()
internal.boot.application // ApplicationDefinition

internal.safeExec​

Runs a callback, catches any thrown error, and logs it instead of propagating. Returns undefined on error.

await internal.safeExec({
context,
exec: async () => {
await riskyOperation();
},
});

internal.removeFn​

Creates a RemoveCallback — a function that is both directly callable and has a .remove() method. Useful for cleanup patterns where you want to support both callback() and callback.remove() call styles:

const cleanup = internal.removeFn(() => { closeConnection(); });

cleanup(); // works
cleanup.remove(); // also works

Module services​

After declaring LoadedModules, your application and library services appear on TServiceParams under their module names:

export function MyService({ my_app, my_lib }: TServiceParams) {
my_app.otherService.doThing();
my_lib.httpClient.get("/items");
}

TypeScript infers the type of each key from the corresponding module's service return types.

Interactive reference​

Loading...